모든 목록 항목에 동일한 값이 있는지 확인하고 반환하는 방법 또는 그렇지 않은 경우 "otherValue"를 반환하는 방법은 무엇입니까?


122

목록에있는 모든 항목의 값이 같으면 해당 값을 사용해야합니다. 그렇지 않으면 "otherValue"를 사용해야합니다. 이 작업을 수행하는 간단하고 명확한 방법을 생각할 수 없습니다.

컬렉션의 첫 번째 항목에 대한 특수 논리가있는 루프를 작성하는 깔끔한 방법을 참조하십시오 .


다소 건방진 관심을 끌기 위해 Ani의 답변을 사용하겠습니다. stackoverflow.com/questions/4390232/…
Binary Worrier

5
목록이 비어있어서 첫 번째 값이 없으면 어떻게 하시겠습니까? 이 경우 "목록에있는 모든 항목의 값이 같다" 는 것이 사실 입니다. 믿지 않으시면 그렇지 않은 항목을 찾아주세요! 이 상황에서해야 할 일을 정의하지 않습니다. 예외가 발생하고 "기타"값을 반환해야합니까? 아니면 무엇입니까?
Eric Lippert

@Eric, 목록이 비어있을 때 죄송합니다 "기타"값을 반환해야합니다
Ian Ringrose 2010

답변:


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

내가 생각할 수있는 가장 깨끗한 방법. val을 인라인하여 한 줄로 만들 수 있지만 First ()는 n 번 평가되어 실행 시간이 두 배가됩니다.

주석에 지정된 "빈 세트"동작을 통합하려면 위의 두 줄 앞에 한 줄을 더 추가하면됩니다.

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

1
+1, 사용 .Any하면 다른 값이있는 경우 열거를 일찍 종료 할 수 있습니까?
Jeff Ogata

12
@adrift : 시퀀스 All의 요소 x에 도달 하자마자 종료됩니다 x.Value != val. 유사하게, Any(x => x.Value != val)x시퀀스 의 요소 에 도달 하자마자 종료됩니다 x.Value != val. 즉, 모두 AllAny전시 "단락"유사에 &&||(무엇을 효율적이다 All하고 Any있습니다).
jason

@Jason : 정확합니다. All (condition)은 사실상! Any (! condition)이며 둘 중 하나의 평가는 답이 알려지 자마자 종료됩니다.
KeithS 2010

4
return yyy.Skip(1).All(x=>x.Value == val) ? val : otherValue;
미세

100

모두를위한 좋은 빠른 테스트 :

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

1
이것은 Class구조체와 함께 작동해야하지만 어떤에서도 작동하지 않습니다 . 그러나 기본 요소 목록에는 좋습니다.
Andrew Backer

2
KeithS의 솔루션 IMO보다 훨씬 더 깨끗합니다. collection.Distinct().Count() <= 1 빈 컬렉션을 허용하려는 경우 사용할 수 있습니다 .
3dGrabber

4
조심, .Distinct()당신은 객체로 작업 할 때 특히, 참조 - 항상 예상대로 작동하지 않습니다 질문을. 이 경우 IEquatable 인터페이스를 구현해야합니다.
Matt

16
예, 그러나 평균적인 경우 성능이 떨어집니다. Distinct ()는 컬렉션의 모든 단일 요소를 한 번 순회하는 것이 보장되며, 모든 요소가 다른 최악의 경우 Count ()는 전체 목록을 두 번 순회합니다. Distinct ()는 또한 HashSet을 생성하므로 그 동작은 NlogN 또는 더 나쁘지 않고 선형이 될 수 있으며 메모리 사용량이 증가합니다. All ()은 모든 요소가 동일한 최악의 경우 하나의 전체 패스를 만들고 새 컬렉션을 생성하지 않습니다.
KeithS

1
@KeithS 지금 쯤이면 알기를 바라며 Distinct, 컬렉션을 전혀 탐색하지 않고 의 반복자 Count를 통해 한 번의 탐색을 수행 Distinct합니다.
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이라고 가정합니다. 이 경우 시퀀스가 ​​비어 있거나 시퀀스의 모든 항목이 추출 된 값에 널을 가질 수 있습니다. 이 경우 통합 은 실제로 (아마도) 올바른 응답이었을 other때를 반환합니다 null. 기능이 T Unanimous<U, T>(this IEnumerable<U> sequence, T other)약간 복잡해 지거나 그러한 서명 이라고 가정 해보십시오 .
Anthony Pegram

@Anthony : 실제로 여기에는 많은 문제가 있지만 쉽게 해결할 수 있습니다. 편의상 nullable int를 사용하여 "I 've seen the first item already"플래그를 선언 할 필요가 없습니다. 깃발을 쉽게 선언 할 수 있습니다. 또한 T 대신 "int"를 사용하고 있습니다. 두 개의 T가 아닌 경우 항상 두 개의 정수를 비교할 수 있다는 것을 알고 있기 때문입니다. 이것은 완전한 기능의 일반 솔루션 이라기보다는 솔루션의 스케치에 가깝습니다.
Eric Lippert

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-그래서 내 대답의 두 번째 부분을 추가했습니다. 작은 컬렉션에서 First ()를 호출하는 것은 간단합니다. 대규모 컬렉션에서는 문제가 될 수 있습니다.
Justin Niessner 2010

1
"소규모 컬렉션에서 First ()를 호출하는 것은 간단합니다." -컬렉션의 출처에 따라 다릅니다. 간단한 개체의 목록 또는 배열의 경우 절대적으로 맞습니다. 그러나 일부 열거 형은 유한 메모리 캐시 된 기본 집합 집합이 아닙니다. 알고리즘 계열 계산 (예 : 피보나치)을 통해 생성되는 델리게이트 컬렉션 또는 열거자는 매번 First ()를 평가하는 데 매우 많은 비용이 듭니다.
KeithS 2010

5
또는 쿼리가 데이터베이스 쿼리이고 "First"를 호출하면 매번 데이터베이스를 다시 조회합니다.
Eric Lippert

1
파일에서 읽는 것과 같은 일회성 반복이 있으면 더 나빠집니다. 그래서 다른 스레드에서 Ani의 답변이 가장 좋습니다.
Alexei Levenkov 2010

@Eric-어서. 아무것도 잘못 각 요소 ... - P에 대한 데이터베이스를 세 번 명중있다
저스틴 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Ʀ 2015

명령 줄에서 릴리스 빌드로 실행하면 다른 결과를 얻을 수 있습니다.
Ian Ringrose 2015

콘솔 응용 프로그램을 HashSet<T>만들었고 내 대답에 LINQ 문을 사용하는 것보다 처음에는 더 빠릅니다. 그러나 루프에서이 작업을 수행하면 LINQ가 더 빠릅니다.
Ɖiamond ǤeezeƦ

이 솔루션 의 가장 큰 문제는 사용자 정의 클래스를 사용하는 경우 GetHashCode()올바르게 수행하기 어려운 자체를 구현해야 한다는 것 입니다. 자세한 내용은 stackoverflow.com/a/371348/2607840 을 참조하십시오.
Cameron

0

위의 단순화 된 접근 방식에 약간의 변형이 있습니다.

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


3
이것은 정확히 반대입니다. 이것은 목록의 모든 요소가 고유한지 확인합니다.
Mario Galea

-1

배열이 아래와 같이 다차원 유형이면 데이터를 확인하기 위해 linq 아래에 써야합니다.

예 : 여기 요소는 0이고 모든 값이 0인지 확인하고 있습니다.
ip1 =
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.