2010-07-18 7 views
65

두 컬렉션의 각 요소에 대한 필드/속성을 비교할 때 하나의 IEnumerable에 다른 IEnumerable의 요소가 모두 포함되어 있는지를 확인하는 가장 빠른 방법은 무엇입니까?하나의 IEnumerable에 다른 IEnumerable의 모든 요소가 포함되어 있는지 확인


public class Item 
{ 
    public string Value; 

    public Item(string value) 
    { 
     Value = value; 
    } 
} 

//example usage 

Item[] List1 = {new Item("1"),new Item("a")}; 
Item[] List2 = {new Item("a"),new Item("b"),new Item("c"),new Item("1")}; 

bool Contains(IEnumerable<Item> list1, IEnumerable<Item>, list2) 
{ 
    var list1Values = list1.Select(item => item.Value); 
    var list2Values = list2.Select(item => item.Value); 

    return //are ALL of list1Values in list2Values? 
} 

Contains(List1,List2) // should return true 
Contains(List2,List1) // should return false 
+1

어떤 방법으로 라운드 당신의 목록은? list1의 모든 항목이 목록 2에 있거나 list2의 모든 항목이 목록 1에 있는지 확인 하시겠습니까? –

답변

94

하나의 컬렉션에있는 모든 값이 다른 컬렉션에 포함되는지 여부를 결정하는 상태를 추적하고 유지 관리하지 않는 한이를 수행하는 "빠른 방법"이 없습니다. 당신이 겨우 IEnumerable<T> 일하는 경우, 나는 Intersect을 사용합니다. Intersect() 한 번만 각 목록을 통해 열거하기 때문에

var allOfList1IsInList2 = list1.Intersect(list2).Count() == list1.Count(); 

이의 성능은 매우 합리적이어야한다. 또한 기본 유형이 IEnumerable<T>이 아닌 ICollection<T> 인 경우 Count()에 대한 두 번째 호출이 최적입니다.

+0

나는 몇 가지 테스트를 수행했으며이 방법은 다른 것보다 빠르게 실행되는 것 같습니다. 팁 고마워. –

+0

당신이'var allOfList2IsInList1 = list1.Intersect (list2) .Count() == list2.Count(); '를 말한 것 같아요. – dan

+2

@fsmmu : 아니에요. 첫 번째 호출은 목록 1과 2의 교집합에있는 항목 수를 찾습니다. 두 번째 호출은 목록 1에있는 항목 수를 찾습니다. 두 숫자가 같은 경우 OP 1에 따라 목록 1에있는 모든 목록 1이 목록 2에 있습니다. 문제. –

2

Linq의 운영자 SequenceEqual 또한 작동 (그러나 동일한 순서 인 열거의 항목에 민감) 것

return list1Uris.SequenceEqual(list2Uris); 
18

C# 3.5

있는지 확인 Enumerable.All<TSource> 사용 모든 List2 항목은 List1에 포함됩니다.

bool hasAll = list2Uris.All(itm2 => list1Uris.Contains(itm2)); 

list1에 list2의 모든 항목보다 많은 항목이 포함되어있는 경우에도 작동합니다.

+8

'All()'호출 내에서'Contains()'호출이 성능에 미치는 영향에 좋지 않습니다. –

+0

또한 그룹 메소드로 이동할 수 있습니다. bool hasAll = list2Uris.All (list1Uris.Contains); – jimpanzer

+0

IEnumerable 유형의 경우이 솔루션은 n * m 성능을 제공합니다. –

31
또한 모든 값이 제거 된 경우 확인 후 두 번째 목록에있는 모든 값을 첫 번째 목록에서 제거하는 경우를 제외하고 사용할 수

:

var allOfList1IsInList2 = !list1.Except(list2).Any(); 

이 방법은 두 가지가 필요없는의 이점이 있었다 Count() 호출.

+0

이것은 List1에는 있지만 List2에는없는 것을 찾는 데 유용합니다. – Homer

+5

이것은 list1에 중복 값이있는 상황에서 작동합니다. 허용 된 대답은 그렇지 않습니다. – dbc

4

답변으로 표시된 해결책은 반복의 경우 실패합니다. IEnumerable에 고유 한 값만 포함되어 있으면 IEnumerable이 전달됩니다.

 int aCount = a.Distinct().Count(); 
     int bCount = b.Distinct().Count(); 

     return aCount == bCount && 
       a.Intersect(b).Count() == aCount; 
3

켄트의 대답은 괜찮 짧은,하지만 그는이 제공하는 솔루션은 항상 전체 첫 컬렉션을 통해 반복을 필요

아래의 대답은 반복 2 개 목록입니다. 다음은 소스 코드입니다.

public static IEnumerable<TSource> Intersect<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer) 
{ 
    if (first == null) 
     throw Error.ArgumentNull("first"); 
    if (second == null) 
     throw Error.ArgumentNull("second"); 
    return Enumerable.IntersectIterator<TSource>(first, second, comparer); 
} 

private static IEnumerable<TSource> IntersectIterator<TSource>(IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer) 
{ 
    Set<TSource> set = new Set<TSource>(comparer); 
    foreach (TSource source in second) 
     set.Add(source); 
    foreach (TSource source in first) 
    { 
     if (set.Remove(source)) 
      yield return source; 
    } 
} 

항상 필요한 것은 아닙니다.

public static bool Contains<T>(this IEnumerable<T> source, IEnumerable<T> subset, IEqualityComparer<T> comparer) 
{ 
    var hashSet = new HashSet<T>(subset, comparer); 
    if (hashSet.Count == 0) 
    { 
     return true; 
    } 

    foreach (var item in source) 
    { 
     hashSet.Remove(item); 
     if (hashSet.Count == 0) 
     { 
      break; 
     } 
    } 

    return hashSet.Count == 0; 
} 

사실, 당신이 ISet<T> (HashSet<T>)를 사용하여 생각해야 : 그래서, 여기 내 솔루션입니다. 여기에는 필요한 모든 설정 메소드가 포함되어 있습니다. 귀하의 경우에는 IsSubsetOf입니다.

-1

은 두 개의 목록

//Method to compare two list 
    private bool Contains(IEnumerable<Item> list1, IEnumerable<Item> list2) 
    { 
     bool result; 

     //Get the value 
     var list1WithValue = list1.Select(s => s.Value).ToList(); 
     var list2WithValue = list2.Select(s => s.Value).ToList(); 

     result = !list1WithValue.Except(list2WithValue).Any(); 

     return result; 
    } 
+0

거의 동일한 대답이 3 년 전에 주어졌습니다. http://stackoverflow.com/a/16967827/5282087 – Dragomok

0

대신 배열의 HashSet의를 사용해야을 비교하기 위해이 방법을 사용할 수 있습니다.

예 :

List1.SetEquals(List2); //returns true if the collections contains exactly same elements no matter the order they appear in the collection 

Reference

유일한 HasSet 제한은 우리가 목록과 같은 인덱스 항목을 들어가거나 사전 같은 키에 의해 아이템을 얻을 수 있다는 것입니다. 당신이 할 수있는 모든 (각각, 등 동안)을 열거입니다

이 당신을 위해 작동하는지 알려 주시기 바랍니다

관련 문제