2011-02-03 4 views
15

可能性の重複:
Test whether two IEnumerable<T> have the same values with the same frequencies2つのIEnumerable <T>がC#で同じ項目を持っている場合、比較する最短の方法は何ですか?

私が更新

を書いた - 修正:

static bool HaveSameItems<T>(this IEnumerable<T> self, IEnumerable<T> other) 
{ 
    return ! 
    ( 
     other.Except(this).Any() || 
     this.Except(other).Any() 
    ); 
} 

が短くな方法ではないですか? 私はSequenceEqualがあることを知っていますが、順序は私のために重要ではありません。

+7

あなた自身のコードにはバグがあります。実際に[排他的論理和](http://en.wikipedia.org/wiki/)をチェックしたいので、両方向で「Except」を使用する必要があります。 Exclusive_disjunction)が空です。 –

+0

@ウィム修正! –

+1

これはバグがあります。 '{1、1、2}'と '{1,2,2} 'に対して真を返します。 – jason

答えて

6

注文が問題ではない場合でも、実行可能なオプションとしてSequenceEqualを除外しません。

var lst1 = new [] { 2,2,2,2 }; 
var lst2 = new [] { 2,3,4,5 }; 
var lst3 = new [] { 5,4,3,2 }; 

//your current function which will return true 
//when you compare lst1 and lst2, even though 
//lst1 is just a subset of lst2 and is not actually equal 
//as mentioned by Wim Coenen 
(lst1.Count() == lst2.Count() && 
     !lst1.Except(lst2).Any()); //incorrectly returns true 

//this also only checks to see if one list is a subset of another 
//also mentioned by Wim Coenen 
lst1.Intersect(lst2).Any(); //incorrectly returns true 

//So even if order doesn't matter, you can make it matter just for 
//the equality check like so: 
lst1.OrderBy(x => x).SequenceEqual(lst2.OrderBy(x => x)); //correctly returns false 
lst3.OrderBy(x => x).SequenceEqual(lst2.OrderBy(x => x)); // correctly returns true 
+1

これは 'O(n log n)'です。 'O(n)'解が存在します。 – jason

+0

参照http://stackoverflow.com/questions/4576723/c-and-linq-want-1-1-2-3-1-2-3-1-returns-true-but-1-1-2- 3-1-2-3-re/4576854#4576854 O(n)LINQベースのソリューション。 – Gabe

+0

私は質問のサンプルを –

6

ここでは一度だけ、各シーケンスを歩くO(n)溶液(実際には、それも完全に第二の配列を歩いていない可能性があります、それは早期終了の可能性があります)です。このソリューションへ

public static bool HaveSameItems<T>(IEnumerable<T> a, IEnumerable<T> b) { 
    var dictionary = a.GroupBy(x => x).ToDictionary(g => g.Key, g => g.Count()); 
    foreach(var item in b) { 
     int value; 
     if (!dictionary.TryGetValue(item, out value)) { 
      return false; 
     } 
     if (value == 0) { 
      return false; 
     } 
     dictionary[item] -= 1; 
    } 
    return dictionary.All(x => x.Value == 0); 
} 

一つの欠点は、それはLINQとSQL、EF、NHiberateなどとうまく相互作用するつもりはないということです。

+0

'e'を' using'文で囲むか、 'foreach'(' while e.MoveNext() 'アプローチの何かの理由?)で行きます。 –

+0

@ダンタオ:良い点。理由はありません、それはただ私に自然に来たものです。 – jason

+0

@ジェイソン:あなたが言ったように、これは明らかにO(n)なので面白いです。それでも私はそれを見つめ続けて、「しかし、もっと良い方法でなければならない」と思っています。なぜかわからない。 –

関連する問題