문제

목록이 비어 있는지 확인하는 "가장 좋은"(속도와 가독성을 모두 고려) 방법은 무엇입니까?목록이 다음 유형인 경우에도 IEnumerable<T> Count 속성이 없습니다.

지금 나는 이 사이에서 고민 중입니다.

if (myList.Count() == 0) { ... }

이:

if (!myList.Any()) { ... }

내 생각에는 두 번째 옵션이 첫 번째 항목을 보는 즉시 결과로 돌아오므로 더 빠른 것 같습니다. 반면 두 번째 옵션(IEnumerable의 경우)은 개수를 반환하기 위해 모든 항목을 방문해야 합니다.

그러면 두 번째 옵션이 읽기 쉬워 보이나요?어느 걸 더 선호하십니까?아니면 빈 목록을 테스트하는 더 좋은 방법을 생각할 수 있습니까?

편집하다 @lassevk의 응답은 다음과 같이 가능한 경우 캐시된 개수를 사용하기 위한 약간의 런타임 검사와 결합되어 가장 논리적인 것 같습니다.

public static bool IsEmpty<T>(this IEnumerable<T> list)
{
    if (list is ICollection<T>) return ((ICollection<T>)list).Count == 0;

    return !list.Any();
}
도움이 되었습니까?

해결책

당신은 이것을 할 수 있습니다 :

public static Boolean IsEmpty<T>(this IEnumerable<T> source)
{
    if (source == null)
        return true; // or throw an exception
    return !source.Any();
}

편집하다:기본 소스에 실제로 빠른 Count 속성이 있는 경우 .Count 메서드를 사용하는 것만으로도 속도가 빨라집니다.위의 유효한 최적화는 몇 가지 기본 유형을 감지하고 .Any() 접근 방식 대신 해당 유형의 .Count 속성을 사용하는 것입니다. 그러나 보장할 수 없는 경우 .Any()로 대체됩니다.

다른 팁

귀하가 결정한 것으로 보이는 코드에 한 가지 작은 추가 사항을 추가하겠습니다.또한 확인하십시오 ICollection, 이는 사용되지 않는 일부 일반 클래스에서도 구현되기 때문입니다(예: Queue<T> 그리고 Stack<T>).나도 사용할 것이다 as 대신에 is 더 관용적이고 더 빠른 것으로 나타났습니다.

public static bool IsEmpty<T>(this IEnumerable<T> list)
{
    if (list == null)
    {
        throw new ArgumentNullException("list");
    }

    var genericCollection = list as ICollection<T>;
    if (genericCollection != null)
    {
        return genericCollection.Count == 0;
    }

    var nonGenericCollection = list as ICollection;
    if (nonGenericCollection != null)
    {
        return nonGenericCollection.Count == 0;
    }

    return !list.Any();
}

LINQ 자체는 어떻게든 Count() 메서드를 중심으로 심각한 최적화를 수행해야 합니다.

이것이 당신을 놀라게 합니까?나는 그것을 상상한다. IList 구현, Count 단순히 요소 수를 직접 읽는 동안 Any 쿼리해야합니다 IEnumerable.GetEnumerator 메소드, 인스턴스 생성 및 호출 MoveNext 적어도 한 번은.

/EDIT @매트:

IEnumerable의 Count() 확장 메서드가 다음과 같은 작업을 수행한다고 가정할 수 있습니다.

예, 물론 그렇습니다.이것이 내가 의미하는 바입니다.실제로는 ICollection 대신에 IList 하지만 결과는 같습니다.

방금 간단한 테스트를 작성했습니다. 다음을 시도해 보세요.

 IEnumerable<Object> myList = new List<Object>();

 Stopwatch watch = new Stopwatch();

 int x;

 watch.Start();
 for (var i = 0; i <= 1000000; i++)
 {
    if (myList.Count() == 0) x = i; 
 }
 watch.Stop();

 Stopwatch watch2 = new Stopwatch();

 watch2.Start();
 for (var i = 0; i <= 1000000; i++)
 {
     if (!myList.Any()) x = i;
 }
 watch2.Stop();

 Console.WriteLine("myList.Count() = " + watch.ElapsedMilliseconds.ToString());
 Console.WriteLine("myList.Any() = " + watch2.ElapsedMilliseconds.ToString());
 Console.ReadLine();

두 번째는 거의 3배 느립니다 :)

스택이나 배열 또는 기타 시나리오를 사용하여 스톱워치 테스트를 다시 시도하면 실제로는 목록 유형에 따라 달라집니다. 왜냐하면 카운트가 더 느리다는 것을 증명하기 때문입니다.

그래서 그것은 당신이 사용하는 목록의 유형에 달려 있다고 생각합니다!

(그냥 지적하자면, 목록에 2000개 이상의 개체를 넣었는데 다른 유형과 반대로 개수가 여전히 더 빨랐습니다.)

List.Count Microsoft 문서에 따르면 O(1)입니다.
http://msdn.microsoft.com/en-us/library/27b47ht3.aspx

그러니 그냥 사용하세요 List.Count == 0 쿼리보다 훨씬 빠릅니다

이는 목록에 무언가가 추가되거나 제거될 때마다 업데이트되는 Count라는 데이터 멤버가 있기 때문입니다. List.Count 요소를 얻기 위해 모든 요소를 ​​반복할 필요는 없으며 단지 데이터 멤버만 반환합니다.

항목이 여러 개인 경우 두 번째 옵션이 훨씬 더 빠릅니다.

  • Any() 1개 항목이 발견되는 즉시 반환됩니다.
  • Count() 전체 목록을 계속 살펴봐야 합니다.

예를 들어 열거에 1000개의 항목이 있다고 가정합니다.

  • Any() 첫 번째 것을 확인한 다음 true를 반환합니다.
  • Count() 전체 열거형을 순회한 후 1000을 반환합니다.

조건자 재정의 중 하나를 사용하는 경우 이는 잠재적으로 더 나쁩니다. 일치 항목이 하나만 있어도 Count()는 여전히 모든 단일 항목을 확인해야 합니다.

Any를 사용하는 데 익숙해지면 의미가 있고 읽기 쉽습니다.

한 가지 주의 사항 - IEnumerable이 아닌 목록이 있는 경우 해당 목록의 Count 속성을 사용하세요.

@Konrad 나를 놀라게 한 것은 내 테스트에서 목록을 허용하는 메서드에 전달한다는 것입니다. IEnumerable<T>, 이므로 런타임은 Count() 확장 메서드를 호출하여 이를 최적화할 수 없습니다. IList<T>.

IEnumerable의 Count() 확장 메서드가 다음과 같은 작업을 수행한다고 가정할 수 있습니다.

public static int Count<T>(this IEnumerable<T> list)
{
    if (list is IList<T>) return ((IList<T>)list).Count;

    int i = 0;
    foreach (var t in list) i++;
    return i;
}

...즉, 특별한 경우에 대한 약간의 런타임 최적화입니다. IList<T>.

/EDIT @Konrad +1 친구 - 당신 말이 맞을 가능성이 더 높습니다 ICollection<T>.

좋아, 그럼 이건 어때?

public static bool IsEmpty<T>(this IEnumerable<T> enumerable)
{
    return !enumerable.GetEnumerator().MoveNext();
}

편집하다:누군가가 이미 이 솔루션을 스케치했다는 것을 방금 깨달았습니다.Any() 메서드가 이 작업을 수행한다고 언급되었지만 직접 수행해 보는 것은 어떨까요?문안 인사

또 다른 아이디어:

if(enumerable.FirstOrDefault() != null)

그러나 나는 Any() 접근 방식을 더 좋아합니다.

이는 Entity Framework에서 작동하도록 하는 데 매우 중요했습니다.

var genericCollection = list as ICollection<T>;

if (genericCollection != null)
{
   //your code 
}

Count()로 확인하면 Linq가 데이터베이스에서 "SELECT COUNT(*).."를 실행하지만 결과에 데이터가 포함되어 있는지 확인해야 하므로 Count() 대신 FirstOrDefault()를 도입하기로 결정했습니다.

전에

var cfop = from tabelaCFOPs in ERPDAOManager.GetTable<TabelaCFOPs>()

if (cfop.Count() > 0)
{
    var itemCfop = cfop.First();
    //....
}

후에

var cfop = from tabelaCFOPs in ERPDAOManager.GetTable<TabelaCFOPs>()

var itemCfop = cfop.FirstOrDefault();

if (itemCfop != null)
{
    //....
}
private bool NullTest<T>(T[] list, string attribute)

    {
        bool status = false;
        if (list != null)
        {
            int flag = 0;
            var property = GetProperty(list.FirstOrDefault(), attribute);
            foreach (T obj in list)
            {
                if (property.GetValue(obj, null) == null)
                    flag++;
            }
            status = flag == 0 ? true : false;
        }
        return status;
    }


public PropertyInfo GetProperty<T>(T obj, string str)

    {
        Expression<Func<T, string, PropertyInfo>> GetProperty = (TypeObj, Column) => TypeObj.GetType().GetProperty(TypeObj
            .GetType().GetProperties().ToList()
            .Find(property => property.Name
            .ToLower() == Column
            .ToLower()).Name.ToString());
        return GetProperty.Compile()(obj, str);
    }

다음은 술어를 허용하는 Dan Tao의 답변 구현입니다.

public static bool IsEmpty<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
    if (source == null) throw new ArgumentNullException();
    if (IsCollectionAndEmpty(source)) return true;
    return !source.Any(predicate);
}

public static bool IsEmpty<TSource>(this IEnumerable<TSource> source)
{
    if (source == null) throw new ArgumentNullException();
    if (IsCollectionAndEmpty(source)) return true;
    return !source.Any();
}

private static bool IsCollectionAndEmpty<TSource>(IEnumerable<TSource> source)
{
    var genericCollection = source as ICollection<TSource>;
    if (genericCollection != null) return genericCollection.Count == 0;
    var nonGenericCollection = source as ICollection;
    if (nonGenericCollection != null) return nonGenericCollection.Count == 0;
    return false;
}
List<T> li = new List<T>();
(li.First().DefaultValue.HasValue) ? string.Format("{0:yyyy/MM/dd}", sender.First().DefaultValue.Value) : string.Empty;

myList.ToList().Count == 0.그게 다야

이 확장 방법은 나에게 효과적입니다.

public static bool IsEmpty<T>(this IEnumerable<T> enumerable)
{
    try
    {
        enumerable.First();
        return false;
    }
    catch (InvalidOperationException)
    {
        return true;
    }
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top