簡體   English   中英

從單個列表創建嵌套的對象列表

[英]Create a nested List of Objects from a single List

我有一個項目列表(不確定它們是偶數還是奇數)。 我想做的是,在這對 5(實際上是一個列表)中提取記錄,創建另一個列表並將這對 5 個列表插入到該新列表中。

謝謝

我可以通過這樣做來創建一組項目

MyList
  .Zip(Enumerable.Range(0, MyList.Count()),
       (s, r) => new { 
          Group = r / 5, 
          Item = s })
  .GroupBy(i => i.Group, 
           g => g.Item)
  .ToList();

但我想生成一個嵌套列表。

不確定我是否正確理解您的目標,但您可以嘗試使用 Dictionary :

MyList.Zip(Enumerable.Range(0, MyList.Count()),
  (s, r) => new { Group = r / 5, Item = s })
.GroupBy(i => i.Group, g => g.Item)
.ToDictionary(g => g.Key, g => g.ToList());

如果你有一個項目集合

var items = Enumerable.Range(1, 20);

你想一次拿 5 個

var setSize = 5;

您可以按索引遍歷集合,並一次將 5 個作為列表,並將所有 5 個列表放入一個外部列表

 Enumerable.Range(0, items.Count() - setSize).Select(x => items.Skip(x).Take(setSize).ToList()).ToList()

結果(來自 C# 交互式外殼)看起來像

List<List<int>>(15) { 
    List<int>(5) { 1, 2, 3, 4, 5 }, 
    List<int>(5) { 2, 3, 4, 5, 6 }, 
    List<int>(5) { 3, 4, 5, 6, 7 }, 
    List<int>(5) { 4, 5, 6, 7, 8 }, 
    List<int>(5) { 5, 6, 7, 8, 9 }, 
    List<int>(5) { 6, 7, 8, 9, 10 }, 
    List<int>(5) { 7, 8, 9, 10, 11 }, 
    List<int>(5) { 8, 9, 10, 11, 12 }, 
    List<int>(5) { 9, 10, 11, 12, 13 }, 
    List<int>(5) { 10, 11, 12, 13, 14 }, 
    List<int>(5) { 11, 12, 13, 14, 15 }, 
    List<int>(5) { 12, 13, 14, 15, 16 }, 
    List<int>(5) { 13, 14, 15, 16, 17 }, 
    List<int>(5) { 14, 15, 16, 17, 18 }, 
    List<int>(5) { 15, 16, 17, 18, 19 }
}

如果您希望每個項目在每個列表中只顯示一次,您可以更改上述內容。 假設有奇數個元素:

var items = Enumerable.Range(1, 11);

您想要更改用於索引到您的集合的初始范圍。 它不會在每個索引上一次取 5 個,而是每次迭代將索引向上跳 5 個。 唯一棘手的部分是確保在集合划分您想要獲取的元素數量時進行處理; 你不想最后得到一個空列表。 也就是說,這是不正確的:

Enumerable.Range(0, items.Count() / setSize).Select( // don't do this

那么聲明是

Enumerable.Range(0, ((items.Count() - 1) / setSize) + 1).Select(x => items.Skip(setSize * x).Take(setSize).ToList()).ToList();

結果(來自 C# 交互式外殼)看起來像

List<List<int>>(3) {
    List<int>(5) { 1, 2, 3, 4, 5 },
    List<int>(5) { 6, 7, 8, 9, 10 },
    List<int>(1) { 11 }
}

看起來您想批量處理元素,每批 5 個項目。 MoreLinq package 已經為此提供了批處理運算符:

var items=Enumerable.Range(0,17);
var batches=items.Batch(5);

foreach(var batch in batches)
{
   Console.WriteLine(String.Join(" - ",batch));
}

這會產生:

0 - 1 - 2 - 3 - 4
5 - 6 - 7 - 8 - 9
10 - 11 - 12 - 13 - 14
15 - 16

這比分組要快得多,因為它只迭代一次集合。

MoreLINQ 也有其他運算符,例如Window 、 WindowLeft 和 WindowRight ,它們會產生滑動的 windows 值。 items.Window(5)將產生:

0 - 1 - 2 - 3 - 4
1 - 2 - 3 - 4 - 5
...
11 - 12 - 13 - 14 - 15
12 - 13 - 14 - 15 - 16

實施

該運算符的實現非常簡單,您只需將其復制到您的項目中即可:

public static IEnumerable<IEnumerable<TSource>> Batch<TSource>(this IEnumerable<TSource> source, int size)
{
    return Batch(source, size, x => x);
}

public static IEnumerable<TResult> Batch<TSource, TResult>( IEnumerable<TSource> source, int size,
    Func<IEnumerable<TSource>, TResult> resultSelector)
{
    if (source == null) throw new ArgumentNullException(nameof(source));
    if (size <= 0) throw new ArgumentOutOfRangeException(nameof(size));
    if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));

    return _(); IEnumerable<TResult> _()
    {
        TSource[] bucket = null;
        var count = 0;

        foreach (var item in source)
        {
            if (bucket == null)
            {
                bucket = new TSource[size];
            }

            bucket[count++] = item;

            // The bucket is fully buffered before it's yielded
            if (count != size)
            {
                continue;
            }

            yield return resultSelector(bucket);

            bucket = null;
            count = 0;
        }

        // Return the last bucket with all remaining elements
        if (bucket != null && count > 0)
        {
            Array.Resize(ref bucket, count);
            yield return resultSelector(bucket);
        }
    }
}

該代碼使用 arrays 來提高效率。 如果您真的想使用可變列表,您可以將bucket的類型更改為List<T> ,例如:

if (bucket == null)
{
   bucket = new List<TSource>(size); //IMPORTANT: set the capacity to avoid reallocations
}

bucket.Add(item);

...

為什么不只是GroupBy

 using System.Linq;

 ...

 int groupSize = 5;

 var result = MyList
   .Select((item, index) => new {
      item,
      index 
    })
   .GroupBy(pair => pair.index / groupSize, 
            pair => pair.item)
   .Select(group => group.ToList())
   .ToList(); 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM