もう一人のY君

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

もう一人のY君 MENU  MENU

【iPhoneショートカット】数字を閉区間、開区間でフィルタする

f:id:thetheorier:20220106085004p:plain

 if文で面倒になる工程を省略します.

 

 

ショートカット

ショートカット

  • Apple
  • 仕事効率化
  • 無料

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

 レビュー時のiOSバージョン : iOS15.2

 

 

スポンサーリンク

 


 

 

入力した数が区間に含まれるかどうか

 if文で使える条件は不等号もしくは等号(の否定)のみです.

 よって指定した区間に含まれるかどうかをif文で判定するにはif文ひとつでは足りません.

 

 

f:id:thetheorier:20220106085043p:plain

 例えばif文を使った例を見てみます.

 区間の端点a,b(a<b)については、今回は「辞書」アクションに用意するやり方で統一します.

 これなら後で好きに値を変えてすぐに実行できます.

 

 

f:id:thetheorier:20220106085217p:plain

 if文を2つ組み合わせ、二つの端点a,bより大きいかどうかで判定します.

 開区間にしたい場合は「次と同じか~」でない方にします.

 

 

f:id:thetheorier:20220106085348p:plain

 一応これで問題なく処理できます.

 しかし条件に一致しない側がバラけてしまうのであまり良いやり方ではありません.

 結果を出力する代わりにフラグやパラメータに置き換え、その結果に従って表示・処理する方法もありますがアクション数が増えるデメリットもあります.

 

 

関数を利用する

 というわけで今回は別の方法を取ります.

 具体的には指定の端点を解とする二次関数を利用します.

 

 

f:id:thetheorier:20220106085710p:plain

 画像の通り、 x=a,b を解とする上に凸の二次関数は f(x)=-(x-a)(x-b) で表すことができます.

  xが例えば x=aより小さい、もしくは x=b より大きければ値は負であり、また一致するなら値は0、あるいは x=a より大きく x=b より小さければ値は正になります.

 つまり入力した値による結果の正負により、指定区間に含まれるかどうか(or端点かどうか)を判定できるということです.

 

 実際には先頭のマイナスは必須ではありません.

 もし取り除いた場合は上に凸から下に凸となり代入した値の正負が逆転するため、判定も逆で考える必要があります.

 

 

f:id:thetheorier:20220106090634p:plain

 まず区間の端点は前回と同じく「辞書」アクションを使います.

 

f:id:thetheorier:20220106090826p:plain

 前回同様、「入力を要求」で数を入力させるまでは同じですが、今回はその後「計算式」アクションを使って

 

 -(x-a)(x-b)

 

を計算させます、レシピの用法で書き換えるなら

 

-(指定入力-a)(指定入力-b)

 

です.

 

 値が正もしくは0に等しいなら入力した値は指定区間(閉区間)に含まれるということですから、この「計算式」の結果が非負なら閉区間[a,b]に含まれ、また正であれば今度は開区間(a,b)に含まれる…と解釈できます.

 

 if文を組み合わせた場合はアクション数が11個でしたがこの方法だと8個に減らせます.

 

 もちろんデメリットもあり、ひとつは二次関数への値の代入であるため値が大きいとオーバーフローすること、もうひとつは小数以下の精度です.

 ショートカットでは小数点以下の精度は16桁程度のようで、それより小さい値は丸められてしまいます.

 

 そのような状況にならないとわかっていればこの方法の方がレシピを見てもわかりやすいですし処理も少ない…とメリットの方が強くなります.

 

 

 

【蛇足】統計量を使った方法

 途中で思いついたアイデアも載せておきます.

 

 統計学で使う指標のひとつに「範囲(range)」があります、具体的には与えられたデータにおける、最大値から最小値を引いたものを言います.

 

 予め与えた二つの端点a,bのみをデータとみなし、その範囲を求めると当然b-aになります.

 そこでこのデータに別の値を追加し、その範囲を求めることを考えます.

 

 もしa以上b以下の値が追加されたならば、それを含むデータの範囲は初期データのそれと変わりません.

 しかしaより小さい、もしくはbより大きい値を追加したデータならば、初期データの範囲より大きくなるはずです.

 

 よって2つの端点のみからなる初期データの範囲と、追加した3つのデータからなる範囲が等しいかどうかを判定することで入力した値が閉区間[a,b]に含まれるかどうかを調べることができる…というやり方です.

 

 

f:id:thetheorier:20220106093039p:plain

 というわけで実際にレシピを組んでみます.

 これまで同様、まずは「辞書」アクションに端点a,b(a>b)を与えます.

 

 

f:id:thetheorier:20220106093145p:plain

 「入力を要求」で新しい数を入力させ、「テキスト」アクションに端点を与えた「辞書」アクションの「値」と「入力を要求」の値を並べます.

 

 この結果はこのままではひとつの塊とみなされているため、「テキストを分割」で改行によって分割しておきます.

 初期データと区別するためにこれを変数に置きます(置き違えなどしない自信があるなら不要です).

 

 

f:id:thetheorier:20220106093502p:plain

 初期データである「辞書」アクションに含まれる値、そして「テキスト」→「テキストを分割」で得た新たなデータそれぞれの範囲を「統計を計算」アクションで求めます.

 

 

f:id:thetheorier:20220106093710p:plain

 上で得た二つの範囲が等しいならば、「入力を要求」で与えた数は閉区間[a,b]に含まれるということです.

 

 

 関数を利用したこのやり方は、他のプログラム言語でも利用できるアイデアだと思います.

 

 複数の区間を一度に扱いたいなら2次関数でなく例えば4次関数を使うことになります.

 ただ次数が増えるとそれだけ値も大きくなる場合があります、やりすぎると上で書いた通りオーバーフローのリスクがあるので使用しないか、他の対策が必要です.

 例えば値が大きくなるのが問題なので、多少複雑になりますが -(x-a)(x-b)であったところをある程度大きな正数 m,n を使って\displaystyle -\left( \frac{x-a}{m} \right)\left( \frac{x-b}{n} \right)とする選択肢もあります.

 ようは結果が正か負か、もしくは0であるか…が分かればよいので、適当な正実数で掛け合わせても目的を果たすことができます.

 ただし m,n が大きすぎると今度は小数点以下の精度問題が影響してきます.

 目的に応じてどちらが適切か選ぶとよいです.

 

 最後に紹介した方法は実用に足るものではないですが「こういうアイデアもあるよ」ということで載せておきました.