プログラミング言語を学び始めて以来、かなり長い間、単純な質問をしてきました。
「x が 1 か 2 の場合 => TRUE (それ以外の場合は FALSE)」のように書きたいと思います。
しかし、プログラミング言語、たとえば C で書くと、
( x == 1 || x == 2 )
それは本当に機能しますが、ぎこちなく読みにくいように見えます。こういう or の操作は簡単にできるのではないかと思うので、何かアイデアがあれば教えてください。ありがとう、ネイサン
プログラミング言語を学び始めて以来、かなり長い間、単純な質問をしてきました。
「x が 1 か 2 の場合 => TRUE (それ以外の場合は FALSE)」のように書きたいと思います。
しかし、プログラミング言語、たとえば C で書くと、
( x == 1 || x == 2 )
それは本当に機能しますが、ぎこちなく読みにくいように見えます。こういう or の操作は簡単にできるのではないかと思うので、何かアイデアがあれば教えてください。ありがとう、ネイサン
Python では、シーケンスのメンバーシップをテストできます。
if x in (1, 2):
C# の拡張バージョン
ステップ 1: 拡張メソッドを作成する
public static class ObjectExtensions
{
public static bool Either(this object value, params object[] array)
{
return array.Any(p => Equals(value, p));
}
}
ステップ 2: 拡張メソッドを使用する
if (x.Either(1,2,3,4,5,6))
{
}
else
{
}
このスレッドには非常に興味深い回答が多数ありますが、言語によってはループ内でこの種のロジックを実行している場合、パフォーマンスに影響を与える可能性があることを指摘したいと思います。コンピューターが理解if (x == 1 || x == 2)
する限りでは、マシン コードにコンパイルされたときに、最も簡単に理解して最適化できます。
プログラミングを始めたとき、次のようなものではなく、奇妙に思えました。
(1 < x < 10)
私は書かなければなりませんでした:
(1 < x && x < 10)
しかし、これがほとんどのプログラミング言語の仕組みであり、しばらくすると慣れるでしょう。
だから私は書くのは完全に問題ないと信じています
( x == 1 || x == 2 )
このように書くと、他のプログラマーがあなたが書いたものを簡単に理解できるという利点もあります。関数を使用してカプセル化すると、他のプログラマーがその関数を見つけてその機能を確認する必要があるため、事態が複雑になる可能性があります。
Python、Ruby などの最近のプログラミング言語だけが、よりシンプルで優れた方法で記述できます。これは主に、これらのプログラミング言語がプログラマーの生産性を向上させるように設計されているためです。一方、古いプログラミング言語の主な目標はアプリケーションのパフォーマンスであり、プログラマーの生産性はそれほど高くありませんでした。
あなたのアプローチは確かにより自然に見えるでしょうが、それは実際に実装に使用する言語に依存します.
Cはシステム プログラミング言語であり、ハードウェアにかなり近い (機械語を書くのではなく、「高水準」言語と見なされていたので面白い)、正確には表現力がありません。
現代の高水準言語(議論の余地はありますが、lisp は歴史的に言えばそれほど現代的ではありませんが、それをうまく行うことができます) では、組み込みの構成要素またはライブラリ サポート (たとえば、Ranges、Python、Ruby、Groovy、ML-languages、Haskellなどの言語のタプルまたは同等のもの。
1 つのオプションは、値の配列を取得してそれらをチェックする関数またはサブルーチンを実装することです。
これが基本的なプロトタイプです。実装は演習として残します。
/* returns non-zero value if check is in values */
int is_in(int check, int *values, int size);
ただし、すぐにわかるように、これは非常に基本的なものであり、あまり柔軟ではありません。
複雑さのはしご (言語の観点から) を 1 段階上げた別の方法として、C (または C++ ) でプリプロセッサ マクロを使用して同様の動作 を実現しますが、副作用に注意してください。
次のステップは、コールポイントでの動作を定義するための追加のパラメーターとして関数ポインターを渡し、これに対していくつかのバリアントとエイリアスを定義し、コンパレーターの小さなライブラリを自分で構築することです。
次のステップは、テンプレートを使用してC++で同様のことを実装し、単一の実装で異なる型に対してこれを行うことです。
そして、そこからさらに高水準言語へと進みます。
通常、関数型プログラミングを好む言語には、明らかな理由から、この種のサポートが組み込まれています。
または、言語によっては、他の言語ではできないことを行うことができ、仕事や環境によっては、それがまさにその通りであることを受け入れることを学ぶだけです。ほとんどがシンタックス シュガーであり、できることはあまりありません。また、仕様を更新することで時間の経過とともに欠点に対処する言語もあれば、失速するだけの言語もあります。
たぶん、ライブラリはすでにそのようなことを実装していて、私は気づいていません。
それは多くの興味深い選択肢でした。誰もスイッチ...ケースについて言及していないことに驚いています-だからここに行きます:
switch(x) {
case 1:
case 2:
// do your work
break;
default:
// the else part
}
えっと、どうしたの?まあ、本当によく使っていて見た目が嫌いなら、C# で次のようにします。
#region minimizethisandneveropen
public bool either(value,x,y){
return (value == x || value == y);
}
#endregion
そして、あなたがそれを使用する場所で:
if(either(value,1,2))
//yaddayadda
または、別の言語でそのようなもの:)。
私はこれを行うことはないと思いますが、あなたの質問に答えるために、ジェネリック型の推論と演算子のオーバーロードの悪用を含む C# でそれを実現する 1 つの方法を次に示します。次のようなコードを記述できます。
if (x == Any.Of(1, 2)) {
Console.WriteLine("In the set.");
}
クラスAny
は次のように定義されています。
public static class Any {
public static Any2<T> Of<T>(T item1, T item2) {
return new Any2<T>(item1, item2);
}
public struct Any2<T> {
T item1;
T item2;
public Any2(T item1, T item2) {
this.item1 = item1;
this.item2 = item2;
}
public static bool operator ==(T item, Any2<T> set) {
return item.Equals(set.item1) || item.Equals(set.item2);
}
// Defining the operator== requires these three methods to be defined as well:
public static bool operator !=(T item, Any2<T> set) {
return !(item == set);
}
public override bool Equals(object obj) { throw new NotImplementedException(); }
public override int GetHashCode() { throw new NotImplementedException(); }
}
}
Any.Of
3 つ、4 つ、またはそれ以上の引数を処理するために、メソッドのオーバーロードが多数ある可能性があります。他の演算子も同様に提供でき、コンパニオンAll
クラスは非常に似たようなことを行うことができますが&&
、代わりに||
.
逆アセンブルを見ると、 を呼び出す必要があるためにかなりのボクシングが発生するため、Equals
これは明らかな構造よりも遅くなります(x == 1) || (x == 2)
。ただし、すべての を に変更して<T>
をint
に置き換えるEquals
と==
、 とほぼ同じ速度でインライン化されているように見えるものが得られます(x == 1) || (x == 2)
。
PHPで使用できます
$ret = in_array($x, array(1, 2));
私の知る限り、C でこれを行う組み込みの方法はありません。x に等しい値の int の配列をスキャンするための独自のインライン関数を追加できます。
そのようです:
inline int contains(int[] set, int n, int x)
{
int i;
for(i=0; i<n; i++)
if(set[i] == x)
return 1;
return 0;
}
// To implement the check, you declare the set
int mySet[2] = {1,2};
// And evaluate like this:
contains(mySet,2,x) // returns non-zero if 'x' is contained in 'mySet'
.Net では、Linq を使用できます。
int[] wanted = new int{1, 2};
// you can use Any to return true for the first item in the list that passes
bool result = wanted.Any( i => i == x );
// or use Contains
bool result = wanted.Contains( x );
||
個人的には、基本は十分に単純だと思いますが:
bool result = ( x == 1 || x == 2 );
COBOL の場合 (COBOL をざっと見たのは久しぶりなので、詳細が 1 つか 2 つ間違っている可能性があります):
IF X EQUALS 1 OR 2
...
したがって、構文は間違いなく可能です。問題は、「なぜあまり使われていないのか」ということになります。
まあ、問題は、そのような式を解析するのはちょっとしたことです。そんな風に一人で立っているときじゃなくて、複合表現のときはもっと。構文は(コンパイラの実装者の観点から)不透明になり始め、セマンティクスは実に毛深いものになります。IIRC、多くの COBOL コンパイラは、潜在的な問題のためにそのような構文を使用すると警告さえします。
T-SQL で
where x in (1,2)
ありがとうイグナシオ!私はそれをRubyに翻訳します:
[ 1, 2 ].include?( x )
それも機能しますが、クリアで正常に見えるかどうかはわかりません. Rubyに詳しい方、教えてください。また、これをCで書く方法を知っている人がいたら教えてください。ありがとう。-ネイサン
Perl6 ::Junctionを使用した Perl 5 :
use Perl6::Junction 'any';
say 'yes' if 2 == any(qw/1 2 3/);
パール 6:
say 'yes' if 2 == 1|2|3;
||
このバージョンは非常に読みやすく簡潔なので、演算子の代わりに使用したいと思います。
Pascal には (限定された) セットの概念があるため、次のようにすることができます。
if x in [1, 2] then
(何十年も Pascal コンパイラに触れていないため、構文がオフになっている可能性があります)
非ビット単位のブール演算子を 1 つだけ使用してみてください (非推奨、未テスト):
if( (x&3) ^ x ^ ((x>>1)&1) ^ (x&1) ^ 1 == 0 )
この(x&3) ^ x
部分は 0 に等しい必要があります。これにより、x が 0 から 3 の間にあることが保証されます。他のオペランドには、最後のビットが設定されるだけです。
^ 1 部分は、((x>>1)&1) ^ (x&1)
最後のビットと最後から 2 番目のビットが異なることを保証します。これは 1 と 2 に適用されますが、0 と 3 には適用されません。
Java では:
List list = Arrays.asList(new Integer[]{1,2});
Set set = new HashSet(list);
set.contains(1)
表記(x==1 || x==2)
が「ぎこちなくて読みにくい」とおっしゃっています。失礼ですが同意できません。自然言語とは違いますが、とても明快で分かりやすいです。コンピューターのように考える必要があります。
また、このスレッドで言及されている表記法は、x in (1,2)
あなたが実際に求めているものとは意味的にx
異なります (1,2)
。あなたが求めているのは、論理的に (そして意味的に)どちらが に変換されるものとif x equals to 1 or to 2
同等かということです。if x equals to 1 or x equals to 2
(x==1 || x==2)
C、C++、VB.net、C#.net、または私が知っている他のどの言語にも、いくつかの選択肢の 1 つをテストする効率的な方法はありません。(x==1 || x==2) は、多くの場合、このような構成をコーディングする最も自然な方法ですが、そのアプローチでは、追加の一時変数の作成が必要になる場合があります。
tempvar = somefunction(); // tempvar は 'if' テストにのみ必要です: if (一時変数 == 1 || 一時変数 == 2) ...
確かに、オプティマイザーは一時変数を効果的に取り除くことができるはずです (使用されている短い時間だけレジスターに押し込みます) が、それでもコードは醜いと思います。さらに、一部の組み込みプロセッサでは、(x == const1 || x==const2 || x==const3) を記述する最もコンパクトでおそらく最速の方法は次のとおりです。
movf _x,w ; 変数 X をアキュムレータにロードする xorlw const1 ; const1 との XOR btfss ステータス、ゼロ; ゼロの場合は次の命令をスキップ xorlw const1 ^ const2 ; (const1 ^ const2) との XOR btfss ステータス、ゼロ; ゼロの場合は次の命令をスキップ xorlw const2 ^ const3 ; (const2 ^ const3) との XOR btfss ステータス、ゼロ; ゼロの場合は次の命令をスキップ いいえ
この方法では、定数ごとにさらに 2 つの命令が必要です。すべての命令が実行されます。早期終了テストは、分岐が行われる場合は時間を節約し、そうでない場合は時間を無駄にします。個別の比較のリテラル解釈を使用するコーディングでは、定数ごとに 4 つの命令が必要になります。
言語に「変数が複数の定数の 1 つである場合」の構造がある場合、コンパイラは上記のコード パターンを使用することを期待します。残念ながら、そのような構造は一般的な言語には存在しません。
(注: Pascal にはそのような構造がありますが、実行時の実装は多くの場合、時間とコード スペースの両方を非常に無駄にします)。
あなたが望むものにいくらか近い、私がよく使うマクロがあります。
#define ISBETWEEN(Var, Low, High) ((Var) >= (Low) && (Var) <= (High))
ISBETWEEN(x, 1, 2)
x が 1 または 2 の場合に true を返します。
x を返す === 1 || x === 2 JavaScriptで