방금 Except()
이 첫 번째 목록에서 두 번째 목록의 모든 요소를 제거하지만 반환 된 결과의 모든 요소를 고유하게 만드는 효과가 있음을 발견했습니다. 내가 사용하고 주위예외는 Distinct와 비슷한 효과가 있습니까?
간단한 방법은 Where(v => !secondList.Contains(v))
사람이이 동작이며,이 설명 문서에 가능하면 포인트 나이 왜 나에게 설명 할 수 있습니까?
방금 Except()
이 첫 번째 목록에서 두 번째 목록의 모든 요소를 제거하지만 반환 된 결과의 모든 요소를 고유하게 만드는 효과가 있음을 발견했습니다. 내가 사용하고 주위예외는 Distinct와 비슷한 효과가 있습니까?
간단한 방법은 Where(v => !secondList.Contains(v))
사람이이 동작이며,이 설명 문서에 가능하면 포인트 나이 왜 나에게 설명 할 수 있습니까?
당신이 쓴 :
간단한 방법으로 주위에 내가 사용하고는이 작업을 수행 할 때, 여전히 중복하지
secondList
으로이 이루어집니다Where(v => !secondList.Contains(v))
입니다. 예를 들어
는 :
var firstStrings = new [] { "1", null, null, null, "3", "3" };
var secondStrings = new [] { "1", "1", "1", null, null, "4" };
var resultStrings = firstStrings.Where(v => !secondStrings.Contains(v)); // 3, 3
나는 전혀 구별이없는 것으로 확장 메서드를 만들었습니다. 사용의 Examle는 :
public static IEnumerable<TSource> ExceptAll<TSource>(
this IEnumerable<TSource> first,
IEnumerable<TSource> second)
{
// Do not call reuse the overload method because that is a slower imlementation
if (first == null) { throw new ArgumentNullException("first"); }
if (second == null) { throw new ArgumentNullException("second"); }
var secondList = second.ToList();
return first.Where(s => !secondList.Remove(s));
}
public static IEnumerable<TSource> ExceptAll<TSource>(
this IEnumerable<TSource> first,
IEnumerable<TSource> second,
IEqualityComparer<TSource> comparer)
{
if (first == null) { throw new ArgumentNullException("first"); }
if (second == null) { throw new ArgumentNullException("second"); }
var comparerUsed = comparer ?? EqualityComparer<TSource>.Default;
var secondList = second.ToList();
foreach (var item in first)
{
if (secondList.Contains(item, comparerUsed))
{
secondList.Remove(item);
}
else
{
yield return item;
}
}
}
편집 : 더 빠른 구현, DigEmAll의 의견에 따라이 원인
:
var result2Strings = firstStrings.ExceptAll(secondStrings).ToList(); // null, 3, 3
이것은 무엇이다
public static IEnumerable<TSource> ExceptAll<TSource>(
this IEnumerable<TSource> first,
IEnumerable<TSource> second)
{
return ExceptAll(first, second, null);
}
public static IEnumerable<TSource> ExceptAll<TSource>(
this IEnumerable<TSource> first,
IEnumerable<TSource> second,
IEqualityComparer<TSource> comparer)
{
if (first == null) { throw new ArgumentNullException("first"); }
if (second == null) { throw new ArgumentNullException("second"); }
var secondCounts = new Dictionary<TSource, int>(comparer ?? EqualityComparer<TSource>.Default);
int count;
int nullCount = 0;
// Count the values from second
foreach (var item in second)
{
if (item == null)
{
nullCount++;
}
else
{
if (secondCounts.TryGetValue(item, out count))
{
secondCounts[item] = count + 1;
}
else
{
secondCounts.Add(item, 1);
}
}
}
// Yield the values from first
foreach (var item in first)
{
if (item == null)
{
nullCount--;
if (nullCount < 0)
{
yield return item;
}
}
else
{
if (secondCounts.TryGetValue(item, out count))
{
if (count == 0)
{
secondCounts.Remove(item);
yield return item;
}
else
{
secondCounts[item] = count - 1;
}
}
else
{
yield return item;
}
}
}
}
More info 내 블로그 (또는 Intersect 및 Union 변종)
이것은 목록에서 항목을 제거하는 것과 같이 각 항목의 목록을 검색하는 것이 비용이 많이 들기 때문에 대단히 비효율적 인 옵션입니다. 'Distinct'라는 언어는 HashSet을 사용하기 때문에 결과적으로 * 훨씬 * 효율적입니다. 효율성을 떨어 뜨리지 않고 소스에서 반복 된 요소를 산출하기 위해 구현을 쉽게 수정할 수 있습니다. – Servy
@Servy에 동의합니다. Contains와 Remove는 모두 O (_n_) 연산이며 루프로 처리하고 있습니다. – Magnus
@Servy, 나는 그것이 더 느리다는 것을 안다. 그러나 결과는 다르다. 이미지에 표시된 것과 같이 더 빠르고 구현 된 구현이 있다면 평론가가 중요합니다. 나는 더 나은 해결책에 호기심이 많다. 효율성을 떨어 뜨리지 않고 소스에서 반복 된 요소를 산출하기 위해 구현을 어떻게 수정합니까? –
글쎄, 좀 더 이해가됩니다. 내가 수학에 착수 한 지 오래되었습니다. 감사. – Stephan
@Stephan - 문서화 된 동작은'IEnumerable'이 시퀀스가 아니라 집합이므로 주어진 목적을위한 범용 확장 메서드를 사용하면 의미 집합 다소 이상합니다. 그런데 다시, IEnumerable 의'Except' 메쏘드가 시퀀스 의미를 가지고 있고'ISet '가'IEnumerable '를 상속 받으면서'ISet '가 의미를 설정 한 대안이 더 나 빠지고 따라서 확장 메소드가 컴파일러에 의해 바인드 된 방법에 따라 의미가 달라질 수 있습니다. –
@ 그렉, 모노는이 [틀린] 것 같다 (http://anonsvn.mono-project.com/viewvc/trunk/mcs/class/System.Core/System.Linq/Enumerable.cs#l794) (이것은 StackOverflow를 통해 실제로 발견 된 두 번째 Mono Enumerable 버그). 처음부터 여러 번 요소를 반환합니다. 내 질문은, 그것이 설정 차이라면 왜 문서가 Enumerable.Ecept 첫 번째 요소의 순서를 유지 보여줍니다 (그것은 또한 "시퀀스"를 반환 말한다)입니까? 세트는 순서를 보존하지 않습니다. 열거 할 수 있습니다. 보장되는 것을 제외하고? –