programing

LINQ: 없음 대 모두 없음

i4 2023. 5. 11. 21:05
반응형

LINQ: 없음 대 모두 없음

종종 제공된 값이 목록의 값과 일치하는지 확인합니다(예: 유효성 검사 시).

if (!acceptedValues.Any(v => v == someValue))
{
    // exception logic
}

최근에 저는 ReSharper가 이러한 쿼리를 다음과 같이 단순화할 것을 요청하는 것을 발견했습니다.

if (acceptedValues.All(v => v != someValue))
{
    // exception logic
}

분명히, 이것은 논리적으로 동일하고, 아마도 조금 더 읽기 쉬울 것입니다. (만약 당신이 수학을 많이 했다면), 제 질문은 이것이 성능에 타격을 주는 결과를 낳을까 하는 것입니다.

그래야 할 것 같은 느낌이 듭니다..Any()짧은 시간인 것처럼 들리지만, 반면에..All()아닌 것처럼 들리지만), 저는 이것을 입증할 것이 없습니다.쿼리가 동일한 문제를 해결할 수 있는지, 아니면 ReSharper가 저를 오해하게 하는지에 대해 더 깊이 알고 있는 사람이 있습니까?

의 구현AllILSpy에 따르면 (내가 실제로 가서 찾아본 것처럼, "음, 그 방법은 약간..."과 같이 작동한다기 보다는, 만약 우리가 영향보다는 이론에 대해 논의한다면, 나는 할 수 있을 것이다.)

public static bool All<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
    if (predicate == null)
    {
        throw Error.ArgumentNull("predicate");
    }
    foreach (TSource current in source)
    {
        if (!predicate(current))
        {
            return false;
        }
    }
    return true;
}

의 구현AnyILSpy에 따르면:

public static bool Any<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
    if (predicate == null)
    {
        throw Error.ArgumentNull("predicate");
    }
    foreach (TSource current in source)
    {
        if (predicate(current))
        {
            return true;
        }
    }
    return false;
}

물론, 생산된 IL에는 약간의 미묘한 차이가 있을 수 있습니다.하지만 아니요, 없습니다.IL은 거의 동일하지만 술어 일치 시 true를 반환하는 것과 술어 불일치 시 false를 반환하는 것의 명백한 반전에 대한 것입니다.

물론 이것은 객체에 대한 링크입니다.다른 linq 공급자가 다른 공급자보다 훨씬 더 잘 처리할 수도 있지만, 그렇다면 어느 쪽이 더 최적의 구현을 얻었는지는 거의 무작위입니다.

그 규칙은 오직 누군가가 느끼는 것으로 귀결되는 것처럼 보일 것입니다.if(determineSomethingTrue)보다 간단하고 가독성이 뛰어납니다.if(!determineSomethingFalse)그리고 공정하게 말하자면, 그들은 제가 종종 발견하는 점에서 약간의 요점을 가지고 있다고 생각합니다.if(!someTest)동일한 장황성과 복잡성에 대한 대체 테스트가 있을 때 혼란* 우리가 행동하고자 하는 조건에 대해 참으로 반환됩니다.하지만 실제로, 저는 개인적으로 당신이 제시하는 두 가지 대안 중 하나보다 하나를 선호할 만한 것을 찾지 못했고, 술어가 더 복잡하다면 아마도 전자 쪽으로 아주 약간 기울었을 것입니다.

*이해할 수 없는 것처럼 혼란스럽지는 않지만, 이해할 수 없는 결정에 미묘한 이유가 있다고 걱정하는 것처럼 혼란스럽고, "아니, 그들은 방금 그렇게 하기로 결정했습니다. 제가 이 코드를 다시 보고 있었던 이유가 무엇입니까?"라는 것을 깨닫기 위해서는 약간의 정신적인 스킵이 필요합니다.."

다음과 같은 확장 방법을 사용하면 코드를 보다 쉽게 읽을 수 있습니다.

public static bool None<TSource>(this IEnumerable<TSource> source)
{
    return !source.Any();
}

public static bool None<TSource>(this IEnumerable<TSource> source, 
                                 Func<TSource, bool> predicate)
{
    return !source.Any(predicate);
}

당신의 원래의 것 대신에 지금.

if (!acceptedValues.Any(v => v == someValue))
{
    // exception logic
}

라고 할 수 있습니다.

if (acceptedValues.None(v => v == someValue))
{
    // exception logic
}

가 나온 에 둘 다 수 있기 둘 다 한 성능을 것입니다. - 가 결 후 중 수 때 있 둘 것 입 다 니 가 성 질 동 을 능 한 일 다 에 문 기 지 할 정 거 를 된 열 둘 에 다 eration ▁bothAny()는 전된술평가첫는번하항서목에째가어로 됩니다.true그리고.All() 번째 는 어가평 가는첫번항서목에째하로 됩니다.false.

All첫 번째 비매치에서 단락이 발생했기 때문에 문제가 없습니다.

한 가지 미묘한 점은

 bool allEven = Enumerable.Empty<int>().All(i => i % 2 == 0); 

사실입니다.순서에 있는 모든 항목이 짝수입니다.

이 방법에 대한 자세한 내용은 Enumerable 설명서를 참조하십시오..

All()시퀀스의 모든 요소가 조건을 충족하는지 여부를 결정합니다.
Any()시퀀스의 요소가 조건을 만족하는지 여부를 결정합니다.

var numbers = new[]{1,2,3};

numbers.All(n => n % 2 == 0); // returns false
numbers.Any(n => n % 2 == 0); // returns true

다른 답들도 잘 다루었듯이, 이것은 성능에 관한 것이 아니라 명확성에 관한 것입니다.

두 가지 옵션을 모두 광범위하게 지원합니다.

if (!acceptedValues.Any(v => v == someValue))
{
    // exception logic
}

if (acceptedValues.All(v => v != someValue))
{
    // exception logic
}

그러나 저는 이것이 더 광범위한 지지를 얻을있다고 생각합니다.

var isValueAccepted = acceptedValues.Any(v => v == someValue);
if (!isValueAccepted)
{
    // exception logic
}

어떤 것을 부정하기 전에 부울을 계산하고 이름을 짓는 것만으로도 제 마음은 이것을 많이 이해할 수 있습니다.

Enumerable 소스를 살펴보면 다음과 같은 기능이 구현되었음을 알 수 있습니다.Any그리고.All상당히 가깝습니다.

public static bool Any<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) {
    if (source == null) throw Error.ArgumentNull("source");
    if (predicate == null) throw Error.ArgumentNull("predicate");
    foreach (TSource element in source) {
        if (predicate(element)) return true;
    }
    return false;
}

public static bool All<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) {
    if (source == null) throw Error.ArgumentNull("source");
    if (predicate == null) throw Error.ArgumentNull("predicate");
    foreach (TSource element in source) {
        if (!predicate(element)) return false;
    }
    return true;
}

유일한 차이점은 부울 부정에 있기 때문에 한 방법이 다른 방법보다 훨씬 빠를 수는 없으므로 잘못된 성능 승리보다 가독성을 선호합니다.

링크에 따라

모두 – 하나 이상의 일치 항목을 확인합니다.

모두 – 모두 일치하는지 확인합니다.

언급URL : https://stackoverflow.com/questions/9027530/linq-not-any-vs-all-dont

반응형