使用LINQ </t> </t>将列表<t>拆分为子列表<t>

时间:2014-11-18 15:53:55

标签: c# linq list split sublist

我有一个包含n Foo项目的List。 Foo包含一个长属性Foo.FileSize。 现在我想将此列表拆分为具有n个元素的子列表,这些元素是FileSize的总和 不超过10000.Cource中有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>();
    }
}

2 个答案:

答案 0 :(得分:0)

老实说,以传统方式而不是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>”的要求,但实际上效率低于直接执行。

答案 1 :(得分:0)

这不是很好,但您可以使用局部变量和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]));