OR / XOR でフラグを操作する
見るだけでは、設定を変えられない
前回、整数に詰め込んだ通知設定を & で読み出しました。読めるようになると、次に困るのは書くほうです。プッシュ通知だけをオンにしたい。SMS だけを今と逆にしたい。ほかの桁は 1 つも触らずに、です。
足し算では駄目です。すでにオンの桁にもう一度足すと繰り上がって、隣の桁を壊します。桁をまたがない演算が要ります。
OR は、消さずに立てる
| は、どちらかが 1 なら 1 を返します。両方が 0 のときだけ 0 です。
プレーンテキスト
0 | 0 = 0
0 | 1 = 1
1 | 0 = 1
1 | 1 = 1立てたい桁だけ 1 のマスクと | を取ると、その桁が 1 になります。もともと 1 だった桁は 1 のまま、マスクが 0 の桁も手つかずです。何度繰り返しても結果が変わらないので、二重にオンにしてしまう心配がありません。
Python
PUSH = 0b010
settings = 0b101 # メールと SMS
settings = settings | PUSH
print(settings) # 7 3 つとも立った
settings = settings | PUSH
print(settings) # 7 何度やっても同じXOR は、押すたびに入れ替わる
^ は、2 つが違うときだけ 1 を返します。同じなら 0 です。
プレーンテキスト
0 ^ 0 = 0
0 ^ 1 = 1
1 ^ 0 = 1
1 ^ 1 = 0マスクの 1 が立っている桁は、0 なら 1 に、1 なら 0 に変わります。マスクが 0 の桁は動きません。つまり ^ は「その桁のスイッチを押す」操作です。
Python
SMS = 0b100
settings = 0b111
settings = settings ^ SMS
print(settings) # 3 SMS が消えた
settings = settings ^ SMS
print(settings) # 7 戻ってきた同じマスクを 2 回当てると元に戻ります。オンとオフを行き来するトグルボタンが、この 1 行で書けます。
| と || は別物
Python なら | と or、JavaScript なら | と || です。字面は似ていますが、前者は桁ごとの計算、後者は式全体を真偽値として見る演算です。
フラグを組み立てているところで or を書くと、桁ごとの計算をしてくれません。0b101 or 0b010 は 0b111 ではなく、左が真なので 0b101 がそのまま返ります。エラーにならず、それらしい数が返ってくるのがたちの悪いところです。
要件
- bits は 0 以上の整数のリスト (同じ値が複数回含まれてもよい)
- ビット OR 演算 (|) を使うこと
- 空配列の場合は 0 を返すこと
入出力例
flagsToInt([0,2,3]) → 13
flagsToInt([0]) → 1
flagsToInt([0,1,2]) → 7
flagsToInt([3]) → 8
flagsToInt([1,1,2]) → 6
flagsToInt([10]) → 1024ヒント
編集 ゆめさく編集部