13

わかったと思いIntersectましたが、間違っていたことがわかりました。

 List<int> list1 = new List<int>() { 1, 2, 3, 2, 3};
 List<int> list2 = new List<int>() { 2, 3, 4, 3, 4};

 list1.Intersect(list2) =>      2,3

 //But what I want is:
 // =>  2,3,2,3,2,3,3

私は次のような方法を理解することができます:

 var intersected = list1.Intersect(list2);
 var list3 = new List<int>();
 list3.AddRange(list1.Where(I => intersected.Contains(I)));
 list3.AddRange(list2.Where(I => intersected.Contains(I)));

これを実現するためのLINQの簡単な方法はありますか?

結果がどの順序で表示されるかは気にしないことを述べる必要があります。

2,2,2,3,3,3,3も完全にOKです。

問題は、これを非常に大きなコレクションで使用していることです。そのため、効率が必要です。

私たちは、intではなくObjectsについて話している。intは簡単な例ですが、これが違いを生む可能性があることを私は理解しています。

4

4 に答える 4

19

私たちがあなたが望むものを正確に特徴づけることができるかどうか見てみましょう。私が間違っている場合は私を訂正してください。必要なもの:リスト1のすべての要素が順番にリスト2にも表示され、続いてリスト2のすべての要素が順番にリスト1にも表示されます。はい?

簡単そうです。

return list1.Where(x=>list2.Contains(x))
     .Concat(list2.Where(y=>list1.Contains(y)))
     .ToList();

これは大きなリストには効率的ではないことに注意してください。リストにそれぞれ1,000個のアイテムがある場合、これは数百万個の比較を行います。そのような状況にある場合は、メンバーシップをテストするために、より効率的なデータ構造を使用する必要があります。

list1set = new HashSet(list1);
list2set = new HashSet(list2);

return list1.Where(x=>list2set.Contains(x))
     .Concat(list2.Where(y=>list1set.Contains(y)))
     .ToList();

これは数千の比較しか行いませんが、より多くのメモリを使用する可能性があります。

于 2010-02-01T21:22:30.043 に答える
1
var set = new HashSet(list1.Intersect(list2));
return list1.Concat(list2).Where(i=>set.Contains(i));
于 2010-02-01T22:00:56.023 に答える
0

多分これは役立つかもしれません:https ://gist.github.com/mladenb/b76bcbc4063f138289243fb06d099dda

元のExcept/Intersectは、コントラクトにそのように記載されていない場合でも、一意のアイテムのコレクションを返します(たとえば、これらのメソッドの戻り値はHashSet / Setではなく、IEnumerableです)。これはおそらく貧弱な結果です。設計上の決定。代わりに、より直感的な実装を使用できます。これは、(Set.Containsを使用して)一意の要素だけでなく、最初の列挙から同じ要素をできるだけ多く返します。

さらに、異なるタイプのコレクションを交差/除外するのに役立つマッピング機能が追加されました。

異なるタイプのコレクションを交差/除外する必要がない場合は、交差/除外のソースコードを調べて、最初の列挙を繰り返す部分を変更して、Set.Add/Set.Removeの代わりにSet.Containsを使用します。

于 2019-04-04T07:37:55.190 に答える
-1

組み込みのAPIではこれが可能だとは思いません。しかし、あなたはあなたが探している結果を得るために以下を使うことができます。

IEnumerable<T> Intersect2<T>(this IEnumerable<T> left, IEnumerable<T> right) {
  var map = left.ToDictionary(x => x, y => false);
  foreach ( var item in right ) {
    if (map.ContainsKey(item) ) {
      map[item] = true;
    }
  }
  foreach ( var cur in left.Concat(right) ) {
    if ( map.ContainsKey(cur) ) {
      yield return cur;
    }
  }
}
于 2010-02-01T21:19:56.427 に答える