通过列表循环的最佳方法是什么? for循环比许多List类的find方法好吗?另外如果我使用它的find methed,如下所述,它是匿名委托谓词委托的一个实例,它是否比使用lambda表达式更好?哪一个会执行得更快?
var result = Books.FindLast(
delegate(Book bk)
{
DateTime year2001 = new DateTime(2001,01,01);
return bk.Publish_date < year2001;
});
答案 0 :(得分:2)
这是一个复杂问题,因为它涉及很多不同的主题。
通常,委托比简单的函数调用慢很多倍,但枚举列表(通过foreach)也非常慢。
如果你真的关心性能(但不要事先做个人资料!)你应该避免代表和枚举。第一个重要步骤(尽可能)可以使用Hashtable而不是简单列表。
现在举一些例子,我将以不同的方式编写相同的函数,从更易读(但更慢)到可读性更低(但更快)。我省略了每个错误检查,但不应该使用真实世界的函数(至少需要一些断言)。
这个函数使用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;
}
现在的示例有点复杂但具有最佳搜索性能。算法来自普通binary search(请注意,如果要匹配与谓词匹配的第一个元素,则可以直接使用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
答案 1 :(得分:2)
使用任何使代码更具可读性的东西。您可以使用lambda表达式简化上面的代码;它们只是匿名委托的简化语法。无论您何时可以使用委托,都可以使用lambda表达式或常规方法。你可以将普通方法作为参数传递而不用括号。
C#编译器实际上只为匿名委托和lambda表达式创建了一个隐藏方法。你可能不会遇到速度上的任何差异。
var result = Books.FindLast(bk => bk.Publish_date < new DateTime(2001,01,01));