如何列出';s的Find(s)方法在C#中有效
本文关键字:方法 有效 Find 何列出 | 更新日期: 2023-09-27 18:28:50
循环列表的最佳方式是什么?for循环比许多List类的find方法好吗?此外,如果我使用下面提到的find方法,即匿名委托谓词委托的实例,这比使用lambda表达式更好吗?哪一个执行得更快?
var result = Books.FindLast(
delegate(Book bk)
{
DateTime year2001 = new DateTime(2001,01,01);
return bk.Publish_date < year2001;
});
这是一个复杂的问题,因为它涉及很多不同的主题。
通常,委托比简单的函数调用慢很多倍,但枚举列表(通过foreach)也非常慢。
如果您真的关心性能(但不要事先这样做,概要!),则应该避免委托和枚举。第一个重要步骤(只要可能)可以是使用哈希表,而不是简单的列表。
示例
现在举几个例子,我将用不同的方式编写相同的函数,从可读性更强(但速度较慢)到可读性较差(但速度较快)。我省略了每一个错误检查,但现实世界中的函数不应该这样做(至少需要一些断言)。
这个函数使用LINQ,它更容易理解,但速度最慢。注意,books
可以是通用枚举(不需要是List<T>
)
public static Book FindLastBookPublishedBefore(IEnumerable<Book> books,
DateTime date)
{
return books.FindLast(x => x.Publish_date < date);
}
与以前相同,但没有LINQ。请注意,此函数处理一个特殊情况:列表中不包含任何符合条件的书籍。
public static Book FindLastBookPublishedBefore(IEnumerable<Book> books,
DateTime date)
{
Book candidate = null;
foreach (Book book in books)
{
if (candidate == null || candidate.Publish_date > book.Publish_date)
candidate = book;
}
return candidate;
}
与以前相同,但没有枚举,请注意此函数处理一个特殊情况:列表中不包含任何符合条件的书籍。
public static Book FindLastBookPublishedBefore(List<Book> books,
DateTime date)
{
Book candidate = null;
for (int i=0; i < books.Count; ++i)
{
if (candidate == null || candidate.Publish_date > books[i].Publish_date)
candidate = books[i];
}
return candidate;
}
与之前相同,但使用了@MaratKhasanov建议的SortedList<T>
。请注意,有了这个容器,您在搜索过程中会有很好的性能,但插入新元素可能比正常的未排序列表更慢(因为列表本身必须保持排序)。如果列表中的元素数量非常多,您可能会考虑使用Hashtable
编写自己的排序列表(例如,使用年份作为第一级的关键字)。
public static Book FindLastBookPublishedBefore(SortedList<Book> books,
DateTime date)
{
Book candidate = null;
for (int i=0; i < books.Count; ++i)
{
DateTime publishDate = books[i].Publish_date;
if (publishDate > date)
return candidate;
if (candidate == null || candidate.Publish_date > publishDate)
candidate = books[i];
}
return candidate;
}
现在是一个稍微复杂一点的示例,但具有最佳搜索性能。算法是从一个普通的二进制搜索中派生出来的(注意,如果你想匹配与谓词匹配的第一个元素,你可以直接使用List.BinarySearch方法)
请注意,代码未经测试,也可以进行优化,请将其视为一个示例。
public static Book FindLastBookPublishedBefore(List<Book> books,
DateTime date)
{
int min = 0, max = books.Count;
Book candidate = null;
while (min < max)
{
int mid = (min + max) / 2;
Book book = books[mid];
if (book.Publish_date > date)
max = mid - 1;
else
{
candidate = book;
++min;
}
if (min >= max)
break;
}
return candidate;
}
在转移到更复杂的容器之前,您可能会考虑在第一次搜索之前保持SortedList<T>
未排序。它会非常慢(因为它也会对列表进行排序),但插入会像普通列表一样快(但你必须尝试使用真实世界的数据)。不管怎样,最后一个算法可以优化很多。
如果你的收藏中有太多的项目,以至于你无法用普通收藏来管理它们,你可能会想把所有的东西都移到数据库中。。。lol
使用任何使代码更可读的东西。您可以通过使用lambda表达式来简化上面的代码;它们只是匿名委托的简化语法。只要可以使用委托,就可以使用lambda表达式或普通方法。您可以将一个普通方法作为参数传递,而不使用括号。
C#编译器实际上只是为匿名委托和lambda表达式创建了一个隐藏方法。您可能不会体验到任何速度差异。
var result = Books.FindLast(bk => bk.Publish_date < new DateTime(2001,01,01));