使用 LINQ 将列表拆分为子列表
本文关键字:列表 拆分 LINQ 使用 | 更新日期: 2023-09-27 18:30:44
我有一个包含n 个 Foo 项目的列表。Foo 包含一个长属性 Foo.FileSize。现在我想将此列表拆分为具有 n 个元素的子列表,这些元素的总和 文件大小不超过 10000。当然,还有一些项目Foo.FileSize超过10000。对于这种特殊情况,只需要一个仅包含此项目的子列表。
请有人可以提出一些建议吗?
const long maxdownloadsize = 10485760;
long actualdownloadsize = 0;
List<TI> downloadTI = new List<TI>();
for (int i = 0; i < comparedTI.Count; i++)
{
var ti = comparedTI[i];
actualdownloadsize += ti.FileSize;
downloadTI.Add(ti);
if (actualdownloadsize > maxdownloadsize || i == comparedTI.Count-1)
{
actualdownloadsize = 0;
AddToList(downloadTI);
downloadTI = new List<TI>();
}
}
老实说,以传统方式而不是使用 Linq 更容易做到这一点,因为序列中每个元素所需的转换方法需要了解所有先前的元素。 所以,你可以做这样的事情:
public static IEnumerable<List<T>> Partition<T>(IEnumerable<T> list, Func<T, long> getValue, long maxSum)
{
long sum = 0;
int partition = 0;
var query = list.Select((i, index) =>
{
if (index == 0)
{
// Reset the external partition counter in case the query is run multiple times.
sum = 0;
partition = 0;
}
var value = getValue(i);
sum = sum + value;
if (sum > maxSum)
{
sum = value;
partition++;
}
return new KeyValuePair<int, T>(partition, i);
})
.GroupBy(pair => pair.Key)
.Select(g => g.Select(pair => pair.Value).ToList());
return query;
}
然后这样称呼它:
var list = new List<Foo>();
// Fill up the list.
var query = Partition(list, f => f.FileSize, 10000);
var partition = query.ToList();
虽然这满足了"使用 LINQ 将List<T>
拆分为Sublists<T>
"的要求,但实际上效率低于直接执行此操作。
这并不漂亮,但您可以使用局部变量和 LINQ GroupBy() 按大小将列表拆分为组。此外,此功能没有优化,因此您可能无法获得最佳数量的组。换句话说,如果列表中间有一个大文件,那么即使可以将更多较小的文件放入当前组,它也会启动一个新组。
var maxGroupSize = 10485760;
var groupId = 0;
var groupCount = 0;
long groupSize = 0;
var groups = files.GroupBy(f =>
{
var size = f.FileSize;
if ((groupCount > 0) && ((groupSize + size) > maxGroupSize))
{
// Start a new group and reset count and sum
groupId++;
groupCount = 0;
groupSize = 0;
}
groupSize += size;
groupCount++;
return groupId;
});
GroupBy
方法返回 IGrouping<TKey, TSource>
,如果需要将其转换为 List,请执行以下操作(假设TSource
类型是从示例代码中TI
的):
List<TI> downloadTI = groups.Select(p => new List<TI>(groups[p.Key]));