拆分对象列表
本文关键字:列表 对象 拆分 | 更新日期: 2023-09-27 18:14:00
那么,下面是我的代码:
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方法?
Update:所有的行和周期按日期排序,并且所有的行总是在这些周期中的一个
更快的方法是在两个结构上执行连接,但是Linq只支持等连接(两个表达式相等的连接)。在您的示例中,您连接的是范围中的一个值,因此不可能使用等连接。
在开始优化之前,确保它需要进行优化。如果这个函数更快,你的程序会明显更快吗?你的应用有多少时间花在这个功能上?
如果优化不会使程序整体受益,那么不要担心它-确保它有效,然后关注程序的其他功能。
也就是说,既然您说行和周期已经按日期排序,那么您可以通过使用循环获得一些性能优势,循环遍历行,直到您走出当前周期,然后移动到下一个周期。至少这样你就不用多次枚举rows
(或periods
)了。
您的代码中有一个小问题:rows
是IEnumerable
,因此它可以被多次枚举。在foreach
。把它改成更稳定的东西是个好主意,比如array,放在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();
优化O(n x m)
算法的最佳机会是在多个连续的O(n)
操作中对其进行转换。为了获得time
,你必须权衡space
,所以如果你基于你的一个Enumerables中的数据创建一些lookup table
,可能会在这种情况下对你有所帮助。
例如,您可以构造一个int
数组,它将为属于一个周期的每一天设置值(每个周期都有另一个已知的硬编码值)。这将是你的第一个O(n)循环。然后你做另一个O(m)循环,只检查与row.Date
对应的数组位置是否为非零(然后你在硬编码的数组中查找实际值,你得到实际的Period
)。
无论如何,这是一个更一般的想法和实现是重要的。如果n和m非常小,您可能不会得到任何好处,但如果它们很大(很大),我可以打赌Split
方法会运行得更快。
假设您使用的所有内容都已经在内存中(不涉及EF)。