もう一人のY君

主にiPhoneのショートカットアプリのレシピやTipsなどを書いています. たまに数学の記事も書きます.

もう一人のY君 MENU  MENU

【iPhoneショートカット】ビットシフトを利用したチェックリスト

f:id:thetheorier:20210907160909p:plain

 先日使えることが分かった論理演算を使って, 簡単なビットシフト操作を検証します.

 

 

ショートカット

ショートカット

  • Apple
  • 仕事効率化
  • 無料

※価格は記事執筆時のものです. 現在の価格はApp Storeから確認ください.

 レビュー時のiOSバージョン : iOS14.7.1

 

 

スポンサーリンク

 


 

 

ビットシフトでフラグ制御

blog.thetheorier.com

 前回の投稿でビットシフトについて紹介しました.

 多少強引ですがショートカットでも整数型変数をビットフラグとして扱うことができることが分かったため, これを使ってチェックリストを作ってみます.

 

 前回分かった通り, (最近の)iPhoneの64ビットなので理屈では一つの数で最大64個のフラグを扱えます.

 つまり一度に最大64項目のチェックリストが作れます(数を一つ扱う場合).

 

 

 予めこちらで決めた方針を先に書いておきます.

 

  1. チェックリストの項目と、それぞれの初期値(flg)を予め与えておく
  2. シフト演算を行うためflgを10進数に変換
    なおチェックするごとにループ処理させるために、「ショートカットの入力」の値が存在するかどうかで処理を分けます、つまり以下のようにします
    「ショートカットの入力」が空
      → 1で与えた初期値(を2で10進にしたもの)をflgに代入
    「ショートカットの入力」が空でない
      → 「ショートカットの入力」をflgに代入
    こうして得たflgをその時点での初期フラグとして採用します
  3. 2で与えられたflgに従ってチェックマークあり・なしのチェックリストを新規作成し、「リストから選択」で選択させます
  4. 3で選択した項目に対応するflgのビット値を反転させます
  5. 4で更新されたflgを10進数変換したものを「ショートカットを実行」する際の入力にします
    これで2回目以降は更新されたflgが「ショートカットの入力」となります

 

 10進変換を除けば, ループ処理での値の引き継ぎの流れは基本的にこうなります.

 初期値を保存したい場合は別の変数を入力として繰り返すことになるでしょう.

 

 

 

レシピ(初期値あり)

 ではレシピです.

 見出しにある通り, 初期値を省略した場合も後に加筆してあります.

 

 

f:id:thetheorier:20210907162536p:plain

 まずチェックリストの核となる項目を「リスト」アクションに書き上げます.

 そして「テキスト」アクションに対応する初期値を入れておきます.

 

 

f:id:thetheorier:20210907162657p:plain

 初期値はビットの値が0のとき「オフ」, 1のとき「オン」ということにし, また下位のビットからリストの順に対応するよう今回は定めています.

 今回はチェックリストなので1がチェックされた状態, 0がチェックが外れた状態を意味します.

 実際には逆にしても構いません, そのときは対応するよう以降の中身を変更することになります.

 

 こういったルール決めに絶対はないですが, 下位ビットから順に項目と対応させるのが普通かなぁ…と思います.

 

イメージ
  データ5 データ4 データ3 データ2 データ1
ビット 5 4 3 2 1

 今回はこういうイメージでチェックのオンオフを決めています.

 例えばデータ1とデータ4だけオン, 残りがオフの場合01001(2)なので10進数で9となります.

 

 本当は「辞書」アクションを使いたいところなんですが, 今回のような扱いをする上で「辞書」アクションは却って使いづらいのでこうなりました.

 

 

f:id:thetheorier:20210907164601p:plain

 というわけで方針通り, 「ショートカットの入力」の有無で場合分けします.

 

 まずは「ショートカットの入力」が空の場合です, このときは最初に決めたバイナリ表記の初期値を10進数に直さねばなりません.

 いくつかの方法がありますが, ここでは前回紹介したシフト演算を使います.

 まず予め初期値としたバイナリ値の桁数を計算しておきます.

 続いて初期値の文字列を1文字ごとに分割し, 「各項目を繰り返す」で各桁ずつ10進に直して足し合わせます.

 n桁のバイナリ値におけるk桁目がa(=0or1)のとき、これは10進数だと\displaystyle a\times 2^{k-1} となります.

 しかし「各項目を繰り返す」では分割したバイナリ値の上位ビットから処理するので実際には

 

\displaystyle \text{繰り返し項目}\times 2^{n-\text{繰り返しインデックス}}

 

としなければなりません.

 この結果を足し合わせて改めてflgとすることで, バイナリ表記だったものが10進に変換されます.

 

 

 「その他の場合」は既に一度以上ループしてflgが「ショートカットの入力」に代入された状態なのでこの「ショートカットの入力」を改めてflgに代入するだけです.

 

 

 

f:id:thetheorier:20210907170927p:plain

 次は方針の3, 上で与えたflgに従ってリストにチェックマークを入れます.

 そのためには特定のビットを取得する必要があります.

 

 例えば11=1011(2)を考えます.

 例えばこの3ビット目をどうやって表現しましょう.

 

 一つの方法として, これを2(=3-1)だけ右にシフトして10(2), 更にこれを2で割った余りをとれば0となって値がわかります.

 

 同じことを10進数で考えてみるとわかると思います.

 例えば123の2桁目を取り出すことを考えます.

 これを1(2-1)桁下げて12, 更に10で割った余りを取って2になりますね.

 

 これを「計算式」アクションで表現すると

 

fmod(flg>>繰り返しインデックス-1,2)

 

となります. (この数式は他でも応用ができます)

 この結果が1ならチェックマーク(好きなものでいいです)を入れた状態の「リストからの項目」を新しい変数(今回はvalue)に追加, 値が0なら「リストからの項目」そのままを新しい変数に追加します.

 これで変数valueがチェックマーク付きの新たなリストとなります.

 

 

f:id:thetheorier:20210907174729p:plain

 上で得られた新しいチェックリストを使って「リストから選択」で項目を選択させます.
 「複数を選択」は好みで設定します.

 複数選択の場合は「完了」をタップする必要があるため手間数がループのたびに1回増えます.

 

 

f:id:thetheorier:20210907175013p:plain

 次は方針の4, 上で選択した項目に対応するフラグを反転させます.

 選択した「繰り返し項目」はチェックマークが付いているため予め外しておき, これ(=アップデートされたテキスト)と元のチェックリストが該当する繰り返し項目(=繰り返し項目2)のインデックス(=繰り返しインデックス2)に対応するフラグのみ反転させればOKです.

 

 ビット反転を行うには論理演算のxorを使います.

 現時点でのフラグであるflgと, 一致するビットの該当箇所 2^{\text{繰り返しインデックス2}-1} のxorを取ればそこだけ反転します.

 

 

f:id:thetheorier:20210908065736p:plain

 最後に「ショートカットを実行」でこのレシピを繰り返します.

 「入力」には変数flgを入れておきます, これを忘れるとチェックした操作が反映されません.

 

 

実行

f:id:thetheorier:20210908065917p:plain

 これで, タップした項目のチェックマークが反転するようになります.

 

 

レシピ(初期値0固定)

 上のレシピが汎用版なので基本的に上の通りで問題ないですが, 初期値がすべて0となるように作る場合はレシピ前半を少し簡単にできます.

 その箇所だけ説明しておきます.

 

 

f:id:thetheorier:20210908070314p:plain

 まずチェックするための項目を「リスト」アクションに書き込むのは前回と同じです.

 

 

f:id:thetheorier:20210908070428p:plain

 初期値が0=000...0(2)なのでバイナリから10進に変換する必要がなくなります.

 そのため最初にflgに代入する操作は単純に0を設定するだけで済みます.

 

 以降のレシピは前回とまったく同じです.

 

 

 汎用版はflgの10進変換の処理だけアクション数が増えるので処理時間は増えますが, 体感では余り違いを感じることはないと思います.