すべてのリストアイテムに同じ値があるかどうかを確認して返す方法、またはそうでない場合は「otherValue」を返す方法


121

リスト内のすべての項目に同じ値がある場合は、その値を使用する必要があります。それ以外の場合は、「otherValue」を使用する必要があります。これを行うための簡単で明確な方法は考えられません。

コレクションの最初の項目に対して特別なロジックを持つループを書くためのきちんとした方法も参照してください


あなたではなく生意気な注意ゲッターで、私はアニの回答でいいと思うstackoverflow.com/questions/4390232/...
バイナリ心配性

5
リストが空で最初の値がない場合はどうしますか?その場合、「リスト内のすべての項目に同じ値がある」というのは本当です-信じられないのなら、違うものを見つけてください!この状況で何をするかは定義しません。これは例外をスローし、「その他」の値を返しますか、それとも何ですか?
Eric Lippert

@Eric、リストが空の場合は申し訳ありませんが、「その他」の値が返されるはずです
Ian Ringrose

回答:


152
var val = yyy.First().Value;
return yyy.All(x=>x.Value == val) ? val : otherValue; 

私が考えることができる最もきれいな方法。valをインライン化することで1行にすることができますが、First()はn回評価され、実行時間が2倍になります。

コメントで指定された「空のセット」の動作を組み込むには、上記の2つの前に1行追加するだけです。

if(yyy == null || !yyy.Any()) return otherValue;

1
+1、.Any異なる値がある場合に列挙を早期に終了するためにallowを使用しますか?
ジェフ緒方

12
@adrift:シーケンスのAll要素xにヒットするとすぐに終了しx.Value != valます。同様に、シーケンスのAny(x => x.Value != val)要素xにヒットするとすぐに終了しx.Value != valます。つまり、両方AllAny展示「短絡」に類似&&して||(事実上何であるAllAnyされています)。
ジェイソン

@ジェイソン:まさに。All(condition)は事実上!Any(!condition)であり、どちらか一方の評価は答えがわかるとすぐに終了します。
KeithS

4
return yyy.Skip(1).All(x=>x.Value == val) ? val : otherValue;
マイクロ最適化

100

すべてが等しい場合の迅速なテスト:

collection.Distinct().Count() == 1

1
これはClassstructでは機能しますが、だけでは機能しません。ただし、プリミティブのリストには最適です。
Andrew Backer 2013

2
+1は、KeithSのソリューションIMOよりはるかにクリーンです。collection.Distinct().Count() <= 1 空のコレクションを許可する場合は、使用 することをお勧めします。
3dGrabber 2013

4
注意してください。.Distinct()常に期待どおりに機能するとは限りません。特にオブジェクトを操作する場合は、この質問を参照してください。その場合、IEquatableインターフェースを実装する必要があります。
マット

16
きれいです。ただし、平均的な場合はパフォーマンスが低下します。Distinct()は、コレクション内のすべての要素を1回トラバースすることが保証されています。最悪の場合、すべての要素が異なる場合、Count()はリスト全体を2回トラバースします。Distinct()はHashSetも作成するため、その動作は線形であり、NlogN以下ではなく、メモリ使用量が増大する可能性があります。All()は、すべての要素が等しいという最悪の場合に1つのフルパスを作成し、新しいコレクションを作成しません。
KeithS 2014

1
@KeithSもう気付くと思いますDistinctが、コレクションをまったく走査しません。CountDistinctの反復子を介して1回走査します。
NetMage

22

このようなデバイスを既存のシーケンスオペレーターから構築することは確かに可能ですが、この場合は、カスタムシーケンスオペレーターとしてこれを作成する傾向があります。何かのようなもの:

// Returns "other" if the list is empty.
// Returns "other" if the list is non-empty and there are two different elements.
// Returns the element of the list if it is non-empty and all elements are the same.
public static int Unanimous(this IEnumerable<int> sequence, int other)
{
    int? first = null;
    foreach(var item in sequence)
    {
        if (first == null)
            first = item;
        else if (first.Value != item)
            return other;
    }
    return first ?? other;
}

これはかなり明確で短く、すべてのケースをカバーし、シーケンスの余分な反復を不必要に作成しません。

これを機能するジェネリックメソッドにすることIEnumerable<T>は、演習として残します。:-)


たとえば、nullableのシーケンスがあり、抽出された値もnullableであるとします。その場合、シーケンスは空である、シーケンス内のすべてのアイテムが抽出された値にnullを持つ可能性があります。この場合、結合は実際に(おそらく)正しい応答であったotherときにを返しnullます。関数がT Unanimous<U, T>(this IEnumerable<U> sequence, T other)そのようなシグネチャであったとすると、少し複雑になります。
Anthony Pegram

@Anthony:実際、ここには多くの複雑な問題がありますが、それらは簡単に回避できます。「最初のアイテムを見たことがある」フラグを宣言する必要がないように、私は便宜上null許容のintを使用しています。フラグを宣言するだけで簡単にできます。また、Tの代わりに「int」を使用しています。これは、2つの整数が等しいかどうかを常に比較できることがわかっているためです。これは、完全に機能する一般的なソリューションというよりは、ソリューションのスケッチです。
Eric Lippert、2010

13
return collection.All(i => i == collection.First())) 
    ? collection.First() : otherValue;.

または、各要素に対してFirst()を実行することを心配している場合(これは有効なパフォーマンスの問題になる可能性があります):

var first = collection.First();
return collection.All(i => i == first) ? first : otherValue;

@KeithS-これが、私の回答の2番目の部分を追加した理由です。小さなコレクションでは、First()の呼び出しは簡単です。大規模なコレクションでは、それが問題になる可能性があります。
Justin Niessner、2010

1
「小さなコレクションでは、First()を呼び出すのは簡単です。」-それはコレクションのソースによって異なります。単純なオブジェクトのリストまたは配列については、あなたの言うとおりです。ただし、一部の列挙可能なものは、メモリキャッシュされた有限のプリミティブセットではありません。デリゲートのコレクション、またはアルゴリズムシリーズ計算(例:フィボナッチ)を介して生成される列挙子は、毎回First()を評価するのに非常にコストがかかります。
KeithS

5
または、クエリがデータベースクエリであり、 "First"を呼び出すと、毎回データベースに再度ヒットします。
Eric Lippert、2010

1
ファイルからの読み取りのような1回限りの反復があると、状況はさらに悪化します...したがって、他のスレッドからのAniの回答が最もよく見えます。
Alexei Levenkov、2010

@エリック-おいおい。各要素についてデータベースに3回アクセスしても問題はありません... :-P
Justin Niessner

3

これは遅いかもしれませんが、Ericの回答に基づいて、値と参照のタイプに同様に機能する拡張機能:

public static partial class Extensions
{
    public static Nullable<T> Unanimous<T>(this IEnumerable<Nullable<T>> sequence, Nullable<T> other, IEqualityComparer comparer = null)  where T : struct, IComparable
    {
        object first = null;
        foreach(var item in sequence)
        {
            if (first == null)
                first = item;
            else if (comparer != null && !comparer.Equals(first, item))
                return other;
            else if (!first.Equals(item))
                return other;
        }
        return (Nullable<T>)first ?? other;
    }

    public static T Unanimous<T>(this IEnumerable<T> sequence, T other, IEqualityComparer comparer = null)  where T : class, IComparable
    {
        object first = null;
        foreach(var item in sequence)
        {
            if (first == null)
                first = item;
            else if (comparer != null && !comparer.Equals(first, item))
                return other;
            else if (!first.Equals(item))
                return other;
        }
        return (T)first ?? other;
    }
}

1
public int GetResult(List<int> list){
int first = list.First();
return list.All(x => x == first) ? first : SOME_OTHER_VALUE;
}

1

LINQを使用する代わりの方法:

var set = new HashSet<int>(values);
return (1 == set.Count) ? values.First() : otherValue;

私はHashSet<T>、最大で6,000までの整数のリストを使用する方が、

var value1 = items.First();
return values.All(v => v == value1) ? value1: otherValue;

まず、これは大量のゴミを作成する可能性があります。また、他のLINQの回答ほど明確ではありませんが、拡張メソッドの回答よりも遅くなります。
Ian Ringrose 2015

そうだね。ただし、小さな値のセットがすべて同じであるかどうかを判断することについて話している場合は、ごみはそれほど多くありません。これを実行し、LINQPadで値の小さなセットに対してLINQステートメントを実行すると、HashSetの方が速かった(Stopwatchクラスを使用して時間を計った)。
ƉiamondǤeezeƦ

コマンドラインからリリースビルドで実行すると、異なる結果が得られる場合があります。
Ian

コンソールアプリケーションを作成し、それHashSet<T>が私の答えでLINQステートメントを使用するよりも最初に速いことがわかりました。ただし、これをループで実行すると、LINQの方が速くなります。
ƉiamondǤeezeƦ

このソリューションの大きな問題は、カスタムクラスを使用している場合は、独自のを実装する必要があることです。GetHashCode()これを正しく行うのは困難です。詳細については、stackoverflow.com / a / 371348/2607840を参照してください。
Cameron

0

上記の簡略化されたアプローチのわずかなバリエーション。

var result = yyy.Distinct().Count() == yyy.Count();


3
これはまったく逆です。これにより、リスト内のすべての要素が一意であることを確認します。
マリオ・ガレア

-1

配列が以下のような多次元型の場合、データをチェックするためにlinqの下に書き込む必要があります。

例:ここでは要素は0で、すべての値が0かどうかを確認しています。
ip1 =
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0

    var value=ip1[0][0];  //got the first index value
    var equalValue = ip1.Any(x=>x.Any(xy=>xy.Equals()));  //check with all elements value 
    if(equalValue)//returns true or false  
    {  
    return "Same Numbers";  
    }else{  
    return "Different Numbers";   
    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.