使用LINQ将列表转换为列表列表

时间:2012-12-12 17:49:26

标签: c# linq

我有一个值列表:

IList<V> values = { V1, V2, V3, V4, V5, V6, V7 };

我想将列表转换为列表列表,其中每个子列表都是指定的大小。每个子列表的大小可能会有所不同。例如:

IList<IList<V>> values_size2 = { { V1, V2 }, { V3, V4 }, { V5, V6 }, { V7 } };
IList<IList<V>> values_size3 = { { V1, V2, V3 }, { V4, V5, V6 }, { V7 } };
IList<IList<V>> values_size4 = { { V1, V2, V3, V4 }, { V5, V6, V7 } };

我可以使用嵌套循环很容易地做到这一点,但是想知道是否有一种聪明的方法可以使用LINQ来做到这一点?

我最初的想法是以某种方式使用Aggregate方法,但不会马上想到任何事情。

感谢。

5 个答案:

答案 0 :(得分:6)

以下是基于IEnumerable的通用Batch功能。您可以将返回类型从IEnumerable<IEnumerable<T>>更改为IEnumerable<IList<T>>而不进行其他更改(因为在我的实现中它已经是一个列表。要更改整个内容以返回您需要的列表列表在结果上调用`ToList,或者做一个更复杂的重构。

请注意,从技术上讲,这不是使用LINQ,它只是创建一个使用LINQ常用的相同样式和模式的新方法。

public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> source
    , int batchSize)
{
    //TODO validate parameters

    List<T> buffer = new List<T>();

    foreach (T item in source)
    {
        buffer.Add(item);

        if (buffer.Count >= batchSize)
        {
            yield return buffer;
            buffer = new List<T>();
        }
    }
    if (buffer.Count >= 0)
    {
        yield return buffer;
    }
}

答案 1 :(得分:5)

您可以使用MoreLINQ批量扩展程序(可从Nuget获得):

IList<IList<V>> values_size2 = values.Batch(2);
IList<IList<V>> values_size3 = values.Batch(3);
IList<IList<V>> values_size4 = values.Batch(4);

您还可以查看来源here

答案 2 :(得分:1)

在 .NET 6 中,您可以使用 new Chunk Linq method

List<IList<V>> values_size2 = values.Chunk(2).ToList();
List<IList<V>> values_size3 = values.Chunk(3).ToList();
List<IList<V>> values_size4 = values.Chunk(4).ToList();

答案 3 :(得分:0)

鉴于其他人的答案,我使用纯LINQ提出了我自己的解决方案,如下所示:

IList<IList<T>> Batch<T>(IList<T> values, int batchSize)
{
    return values.Aggregate(
        new List<IList<T>>(),
        (state, next) => {
            IList<T> batch = (state.Count > 0) ? state[state.Count - 1] : null;
            if ((batch == null) || (batch.Count == batchSize))
            {
                batch = new List<T>(batchSize);
                state.Add(batch);
            }
            batch.Add(next);
            return state;
        });
}

这可能没有使用IEnumerable那么高效,但在我的情况下我处理的是小集,所以它应该没关系。

我将选择Servy的答案作为“正确的”答案,因为它不依赖于外部库并引导我使用我的解决方案。

感谢大家的帮助:)

答案 4 :(得分:0)

 public static IEnumerable<IEnumerable<T>> Chunks<T>(this IEnumerable<T> source, int chunkSize)
 {
     while (source.Any())
     {
         yield return source.Take(chunkSize);
         source = source.Skip(chunkSize);
     }
 }