В PHP (или любом другом языке) Можно ли объединить 2 битовые маски, сохраняя при этом "идентичность" исходных битов?
Возможно, это действительно глупый вопрос, но он просто пришел мне в голову, и я подумал, что было бы интересно узнать наверняка....
Итак, вот сценарий:
У пользователей есть 3 варианта для каждого дня недели: утро, вечер и ВЫХОДНОЙ. Это взаимоисключающие варианты, поэтому нет возможности работать как утром, так и вечером в один и тот же день.
Итак, если бы я хотел сохранить их смены AM и смены PM в виде отдельных битовых масок, а Пользователь1 выбрал бы следующее:
S M T W Th F Sa
A P X A X P A
Я бы хотел следующее:
$shifts['User1']['AM'] = 73; // 1001001
$shifts['User1']['PM'] = 34; // 0100010
Теперь, если бы я просто хотел знать, в какие дни работал Пользователь1, я, очевидно, мог бы просто сделать:
$shifts['User1']['All'] = $shifts['User1']['AM'] | $shifts['User1']['PM'];
Или даже просто:
$shifts['User1']['All'] = $shifts['User1']['AM'] + $shifts['User1']['PM'];
Но что, если бы я хотел, чтобы конечный результат отличал AM от PM, что-то вроде:
$shifts['User1']['AM'] = A00A00A;
$shifts['User1']['PM'] = 0P000P0;
Так что A и P считаются заданными, но это
A00A00A | 0P000P0 = AP0A0PA;
Есть ли общий способ сделать это, или я думаю об этом совершенно неправильно?
5 answers
Для представления трех состояний двоичным способом вам нужно 2 бита. Например, вы могли бы сказать, что:
PM= 01
AM = 10
ВЫКЛ = 00
Итак, теперь у вас есть это:
A00A00A
переводится как 10 00 00 10 00 00 10
0P000P0
переводится как 00 01 00 00 00 01 00
Применение побитовой операции ИЛИ:
10 00 00 10 00 00 10
00 01 00 00 00 01 00
--------------------
10 01 00 10 00 01 10
A P 0 A 0 P A
Вы получаете AP0A0PA
желаемый результат.
Для записи буквального значения в двоичном виде используйте: 0b1001001
или шестнадцатеричное: 0x49
вместо десятичного: 73
.
Растровое изображение всегда будет давать вам только значение true или false, поэтому невозможно представить три значения (AM, PM, X), сжав два растровых изображения в одно.
Я думаю, что вы думаете об этом неправильно (у других может быть более разумное решение, о котором я не могу думать). Массив символов A, P, X может быть так же хорош для этого. Вы можете объединять массивы (так что это не то же самое, что строка).
Да, это возможно. Смотрите пример ниже на Python:
>>> class WorkShift(str):
def __or__(self, val):
def shift_calc(x, y):
return x if x != '0' else y
return WorkShift(''.join(map(shift_calc, self, val)))
>>> WorkShift('A00A00A') | WorkShift('0P000P0')
'AP0A0PA'
Отвечает ли это на ваш вопрос?
Пс. Я использовал Python, так как вы явно заявили, что это может быть любой язык программирования. Я перегрузил оператор |
. Результатом операции по-прежнему является экземпляр WorkShift
, поэтому вы можете использовать его для дальнейшей обработки. Он также наследуется от str
, поэтому вы также можете использовать его в качестве строки.
РЕДАКТИРОВАТЬ:
Аналогичное решение для PHP, но без перегрузки операторов, основано только на обработке строк:
<?php
function shift_calc($x, $y) {
return $x != '0' ? $x : $y;
};
function shift_sum($am, $pm) {
return implode(array_map('shift_calc', str_split($am), str_split($pm)));
};
$result = shift_sum('A00A00A', '0P000P0');
Где $result
- строка со следующим значением: "AP0A0PA
" (см. Доказательство здесь: http://ideone.com/NbTEJ).
Комментарий Minitech верен. Это троичная система счисления (потому что у вас есть 3 варианта для каждого значения). Таким образом, вы могли бы сделать это:
$shifts['User1']['AM'] = '1001001'; // A00A00A
$shifts['User1']['PM'] = '0200020'; // 0P000P0
$all = intval($shifts['User1']['AM'], 3) +
intval($shifts['User1']['PM'], 3);
echo base_convert($all, 10, 3);
Здесь у вас есть два варианта.
-
Чередование
Исходная битовая маска раскладывается, а новая битовая маска вставляется в новые "отверстия".
APAPAPAPAPAPAP
-
Добавить
Новая битовая маска добавляется к старой битовой маске.
AAAAAAAPPPPPPP
Первое легче проверить/сравнить, но второе более эффективно в отношении скорости.