Helpex - Trao đổi & giúp đỡ Đăng nhập
122

Cách "tốt nhất" (lấy cả tốc độ và khả năng đọc vào tài khoản) để xác định xem danh sách có trống không? Ngay cả khi danh sách thuộc loại IEnumerable<T>và không có thuộc tính Count.

Ngay bây giờ tôi đang tung lên giữa đây:

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

và điều này:

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

Tôi đoán là tùy chọn thứ hai nhanh hơn, vì nó sẽ quay lại với kết quả ngay khi nhìn thấy mục đầu tiên, trong khi tùy chọn thứ hai (đối với IEnumerable) sẽ cần truy cập vào mọi mục để trả về số đếm.

Điều đó đang được nói, liệu tùy chọn thứ hai có vẻ dễ đọc đối với bạn? Bạn thích cái nào? Hoặc bạn có thể nghĩ ra một cách tốt hơn để kiểm tra danh sách trống không?

Chỉnh sửa phản hồi của @ lassevk có vẻ hợp lý nhất, cùng với một chút kiểm tra thời gian chạy để sử dụng số lượng được lưu trong bộ nhớ cache nếu có thể, như thế này:

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

    return !list.Any();
}
122 hữu ích 4 bình luận 128k xem chia sẻ
16 trả lời 16
98

Bạn có thể làm điều này:

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

Chỉnh sửa : Lưu ý rằng chỉ cần sử dụng phương thức .Count sẽ nhanh nếu nguồn bên dưới thực sự có thuộc tính Đếm nhanh. Tối ưu hóa hợp lệ ở trên sẽ là phát hiện một vài loại cơ sở và chỉ cần sử dụng thuộc tính .Count của các loại đó, thay vì cách tiếp cận .Any (), nhưng sau đó quay lại .Any () nếu không thể đảm bảo.

98 hữu ích 5 bình luận chia sẻ
14

Tôi sẽ thực hiện một bổ sung nhỏ cho mã mà bạn dường như đã giải quyết: cũng kiểm tra ICollection, vì điều này được thực hiện ngay cả bởi một số lớp chung không lỗi thời (ví dụ, Queue<T>Stack<T>). Tôi cũng sẽ sử dụng asthay vì isnó thành ngữ hơn và đã được chứng minh là nhanh hơn .

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();
}
14 hữu ích 2 bình luận chia sẻ
8

Bản thân LINQ phải thực hiện một số tối ưu hóa nghiêm túc xung quanh phương thức Count ().

Điều này có làm bạn ngạc nhiên không? Tôi tưởng tượng rằng để IListtriển khai, Countchỉ cần đọc trực tiếp số lượng phần tử trong khi Anyphải truy vấn IEnumerable.GetEnumeratorphương thức, tạo một thể hiện và gọi MoveNextít nhất một lần.

/ EDIT @Matt:

Tôi chỉ có thể giả sử rằng phương thức mở rộng Count () cho IEnumerable đang làm một cái gì đó như thế này:

Vâng, tất nhiên là có. Đây là những gì tôi muốn nói. Trên thực tế, nó sử dụng ICollectionthay vì IListnhưng kết quả là như nhau.

8 hữu ích 0 bình luận chia sẻ
6

Tôi vừa viết một bài kiểm tra nhanh, hãy thử điều này:

 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();

Thứ hai là chậm hơn gần ba lần :)

Thử lại kiểm tra đồng hồ bấm giờ với Stack hoặc mảng hoặc các tình huống khác, nó thực sự phụ thuộc vào loại danh sách có vẻ như - bởi vì chúng chứng minh Count chậm hơn.

Vì vậy, tôi đoán nó phụ thuộc vào loại danh sách bạn đang sử dụng!

(Chỉ cần chỉ ra, tôi đã đưa hơn 2000 đối tượng vào Danh sách và số lượng vẫn nhanh hơn, ngược lại với các loại khác)

6 hữu ích 3 bình luận chia sẻ
4

List.Countlà O (1) theo tài liệu của Microsoft:
http://msdn.microsoft.com/en-us/l Library / 274747ht3.aspx

vì vậy chỉ cần sử dụng List.Count == 0nó nhanh hơn nhiều so với truy vấn

Điều này là do nó có một thành viên dữ liệu được gọi là Count được cập nhật bất cứ khi nào một thứ gì đó được thêm hoặc xóa khỏi danh sách, vì vậy khi bạn gọi List.Countnó không phải lặp qua mọi phần tử để lấy nó, nó chỉ trả về thành viên dữ liệu.

4 hữu ích 2 bình luận chia sẻ
3

@Konrad điều làm tôi ngạc nhiên là trong các thử nghiệm của mình, tôi chuyển danh sách vào một phương thức chấp nhận IEnumerable<T>, vì vậy thời gian chạy không thể tối ưu hóa nó bằng cách gọi phương thức mở rộng Count () cho IList<T>.

Tôi chỉ có thể giả sử rằng phương thức mở rộng Count () cho IEnumerable đang làm một cái gì đó như thế này:

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;
}

... Nói cách khác, một chút tối ưu hóa thời gian chạy cho trường hợp đặc biệt của IList<T>.

/ EDIT @Konrad +1 người bạn đời - bạn có nhiều khả năng về điều đó ICollection<T>.

3 hữu ích 0 bình luận chia sẻ
2

Tùy chọn thứ hai nhanh hơn nhiều nếu bạn có nhiều mặt hàng.

  • Any() trả lại ngay khi tìm thấy 1 mục.
  • Count() phải tiếp tục đi qua toàn bộ danh sách.

Ví dụ, giả sử bảng liệt kê có 1000 mục.

  • Any() sẽ kiểm tra cái đầu tiên, sau đó trả về true.
  • Count() sẽ trả lại 1000 sau khi vượt qua toàn bộ bảng liệt kê.

Điều này có khả năng tệ hơn nếu bạn sử dụng một trong các phần ghi đè vị ngữ - Count () vẫn phải kiểm tra từng mục duy nhất, thậm chí nó chỉ có một kết quả khớp.

Bạn đã quen với việc sử dụng Bất kỳ ai - nó có ý nghĩa và có thể đọc được.

Một cảnh báo - nếu bạn có Danh sách, thay vì chỉ là IEnumerable thì hãy sử dụng thuộc tính Count của danh sách đó.

2 hữu ích 1 bình luận chia sẻ
1

Ok, vậy cái này thì sao?

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

EDIT: Tôi vừa nhận ra rằng ai đó đã phác thảo giải pháp này rồi. Nó đã được đề cập rằng phương thức Any () sẽ làm điều này, nhưng tại sao không tự làm? Trân trọng

1 hữu ích 2 bình luận chia sẻ
1

Một ý tưởng khác:

if(enumerable.FirstOrDefault() != null)

Tuy nhiên tôi thích cách tiếp cận Any () hơn.

1 hữu ích 1 bình luận chia sẻ
1

Điều này rất quan trọng để làm cho điều này hoạt động với Entity Framework:

var genericCollection = list as ICollection<T>;

if (genericCollection != null)
{
   //your code 
}
1 hữu ích 1 bình luận chia sẻ
0

Nếu tôi kiểm tra với Count () Linq thực thi "CHỌN COUNT (*) .." trong cơ sở dữ liệu, nhưng tôi cần kiểm tra xem kết quả có chứa dữ liệu hay không, tôi đã quyết định giới thiệu FirstOrDefault () thay vì Count ();

Trước

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

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

Sau

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

var itemCfop = cfop.FirstOrDefault();

if (itemCfop != null)
{
    //....
}
0 hữu ích 0 bình luận chia sẻ
0
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);
    }
0 hữu ích 0 bình luận chia sẻ
0

Đây là cách tôi thực hiện câu trả lời của Dan Tao, cho phép một vị ngữ:

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;
}
0 hữu ích 0 bình luận chia sẻ
1
List<T> li = new List<T>();
(li.First().DefaultValue.HasValue) ? string.Format("{0:yyyy/MM/dd}", sender.First().DefaultValue.Value) : string.Empty;
1 hữu ích 1 bình luận chia sẻ
3

myList.ToList().Count == 0. Đó là tất cả

3 hữu ích 1 bình luận chia sẻ
5

Phương pháp mở rộng này hoạt động với tôi:

public static bool IsEmpty<T>(this IEnumerable<T> enumerable)
{
    try
    {
        enumerable.First();
        return false;
    }
    catch (InvalidOperationException)
    {
        return true;
    }
}
5 hữu ích 5 bình luận chia sẻ
loading
Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ c# .net linq list , hoặc hỏi câu hỏi của bạn.

Có thể bạn quan tâm

loading