Побитовые сжатые Логические значения - Переключение Определенных


Предыстория

Мне нужно хранить несколько значений true/false в базе данных, и вместо того, чтобы создавать много столбцов, я вместо этого использую один столбец int, в котором я храню все логические значения, сжатые с помощью побитовых операторов.

Пример:

Product 1 сертифицирован как:

Lead Free - Yes
Gluton Free - No
Free Range - Yes
Organic - Yes

Поэтому в БД, в столбце certs, я бы сжал 1, 0, 1, 1 в 13 (1 + 4 + 8).

Я написал функции быстрой оболочки для сжатия и извлеките эту информацию (измените из int в массив boolean и обратно).

Проблема

Я не уверен в лучшем способе быстрого добавления и удаления значений из этого. Скажем, я хочу обновить продукт, чтобы он больше не был свободным. Я могу взять сжатый int, минус 4. Это работает. За исключением того, что, если это уже не был Свободный выгул? Если я выполняю массовые операции, мне нужно, чтобы моя функция удаляла только 4 из продуктов, которые в настоящее время сертифицированы в свободном ассортименте, иначе номер будет перепутан вверх.

Я понял это с помощью длинного заявления if, но это не элегантно. Это работает:

// $certs_current is the compressed int from the DB.
// $certs_new is a new integer. 4 would mean toggle "Free Range" to true. -4 would mean toggle it to false.

if ( $certs_current & abs($certs_new) ) {
    if ( $certs_new < 0 ) {
        $certs_current += $certs_new;
    }
} else {
    if ( $certs_new > 0 ) {
        $certs_current += $certs_new;
    }
}

Это много if утверждений. Я поиграл с оператором |, но он работает только для добавления положительных чисел. Передайте ему -4, и он сломается. И я не могу понять оператора nor.

Есть ли лучший способ сделать это?

Редактировать:

Другими словами, есть ли оператор, где: Если я дам ему 13 и -4, он будет дай мне 9. Но если я дам ему 9 и -4, он даст 9? Или даже просто 13 и 4.

Редактировать 2

Добавив в | свою рабочую логику, я уменьшил сложность и все еще работаю:

if ( $certs_new > 0 ) {
    $certs_current = ( $certs_current | $certs_new );
} else {
    if ( $certs_current & abs($certs_new) ) {
        $certs_current += $certs_new;
    }
}

В основном это говорит о том, что если новое число положительное, то используйте оператор |, чтобы добавить его, если его необходимо добавить. Если он отрицательный, то мы сначала проверяем, нужно ли его удалять, и если да, то удаляем его. Это то место, где я думаю, мы сможем исправиться.

| заменяет оператор if, потому что он добавляет 4 только в том случае, если 4 еще не переключено на true (я понял, что это странный способ его описания).

Но с отрицательным числом у меня все еще есть вложенный оператор if, который я хочу удалить, если это возможно.

Author: Andy Mercer, 2017-08-01

2 answers

У вас есть сжатое значение, так почему бы вам не расширить его перед выполнением своих операций?

$certs_temp = $certs_current
$is_organic = $certs_temp >= 8 && $certs_temp -= 8
$is_freerange = $certs_temp >= 4 && $certs_temp -= 4
$is_glutenfree = $certs_temp >= 2 && $certs_temp -= 2
$is_leadfree = $certs_temp >= 1 && $certs_temp -= 1

, А затем повторно сжать с измененными значениями (если действительно что-то изменилось).

Я думаю, что вы напрашиваетесь на неприятности, если попытаетесь работать непосредственно с сохраненным целым числом, которое на самом деле представляет собой 4 отдельных двоичных флага. Либо представляйте каждый флаг отдельно в БД, либо, если он должен храниться в виде целого числа, декодируйте его перед применением изменений или логики.

 0
Author: Peter Abolins, 2017-08-01 13:21:00

Ответ

Я понял это. Чтобы переключить логическое значение на false, нам нужно:

  1. Реверсируйте первичный сжатый int из БД, используя ~ (13 в примере)

  2. Добавьте абсолютное значение нового int 4 (не -4), используя |.

  3. Повторите полный int еще раз, используя ~.

Итак, окончательный код, содержащий только одно утверждение if:

if ( $certs_new > 0 ) {
    $certs = ( $certs | $certs_new );
} else {
    $certs = ~( ~$certs | abs($certs_new) );  
}

// 13 and 4 .... 13
// 13 and 2 .... 15
// 13 and -4 .... 9
// 13 and -2 .... 13
 0
Author: Andy Mercer, 2017-08-01 13:42:55