所以,这是我的代码:
private List<IEnumerable<Row>> Split(IEnumerable<Row> rows,
IEnumerable<DateTimePeriod> periods)
{
List<IEnumerable<Row>> result = new List<IEnumerable<Row>>();
foreach (var period in periods)
{
result.Add(rows.Where(row => row.Date >= period.begin && row.Date <= period.end));
}
return result;
}
private class DateTimePeriod
{
public DateTime begin { get; set; }
public DateTime end { get; set; }
}
正如您所看到的,此代码不是最好的,它会遍历每个时段的所有行。 我需要有关如何优化此代码的建议。也许有适合的Enumerable方法?
更新:按日期排序的所有行和期间,所有行始终处于其中一个期间。
答案 0 :(得分:2)
更快的方法是在两个结构上执行连接,但Linq仅支持等连接(两个表达式相等的连接)。在您的情况下,您正在加入一个值范围值的值,因此无法进行等连接。
在开始优化之前,请确保需要进行优化。如果此功能更快,您的程序会明显更快吗?您在这个功能中花了多少时间?
如果优化不会使整个整体计划受益,那么请不要担心 - 确保它有效,然后专注于该计划的其他功能。
那就是说,因为你说行和句点已经按日期排序了,你可以通过使用循环,循环遍历行直到你超出当前时期,然后转移到下一行来获得一些性能优势期。至少,您不会多次枚举rows
(或periods
)。
答案 1 :(得分:1)
您的代码中存在一些问题:rows
为IEnumerable
,因此可以多次枚举它。在foreach
。将它更改为更稳定的东西是个好主意,比如数组,在foreach的外面:
var myRows = rows as Row[] ?? rows.ToArray();
顺便说一下。我使用 Resharper :将代码更改为以下代码
var myRows = rows as Row[] ?? rows.ToArray();
return periods.Select(period => myRows.Where(row => row.Date >= period.begin && row.Date <= period.end)).ToList();
答案 2 :(得分:-1)
优化O(n x m)
算法的最佳机会是在多个连续O(n)
操作中对其进行转换。为了获得time
,您必须权衡space
,因此,如果您根据其中一个Enumerables中的数据创建一些lookup table
,则可能会在这种情况下为您提供帮助。
例如,您可以构建一个int
数组,该数组将为属于某个时段的每一天设置值(每个时段都有另一个已知的硬编码值)。这将是你的第一个O(n)循环。然后你做另一个O(m)循环并且只检查对应于row.Date
的数组位置是否为非零(然后你在硬编码的那些中查找实际值并得到实际的Period
)。
无论如何,这更像是一个总体思路,实施很重要。如果 n 和 m 非常小,您可能无法获得任何好处,但如果它们很大(巨大),我可以打赌Split
方法会更快地运行
假设您使用的所有内容已经在内存中(不涉及EF)。