[英]Create a nested List of Objects from a single List
I have a list of items (not sure they are even or odd number of items).我有一个项目列表(不确定它们是偶数还是奇数)。 What I wanna do is, pick up records in the pair of 5 (which actually is a list), create another list and insert these pair of 5 lists into that new list.
我想做的是,在这对 5(实际上是一个列表)中提取记录,创建另一个列表并将这对 5 个列表插入到该新列表中。
Thanks谢谢
I can create a group of items by doing this我可以通过这样做来创建一组项目
MyList
.Zip(Enumerable.Range(0, MyList.Count()),
(s, r) => new {
Group = r / 5,
Item = s })
.GroupBy(i => i.Group,
g => g.Item)
.ToList();
But I want to generate a nested list.但我想生成一个嵌套列表。
Not sure I understand your aim correctly, but you can try to use Dictionary for it:不确定我是否正确理解您的目标,但您可以尝试使用 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());
If you have a collection of items如果你有一个项目集合
var items = Enumerable.Range(1, 20);
And you want to take, say, 5 at a time你想一次拿 5 个
var setSize = 5;
You can iterate over the collection by index, and take that 5 at a time as a list, and put all those lists of 5 into one outer list您可以按索引遍历集合,并一次将 5 个作为列表,并将所有 5 个列表放入一个外部列表
Enumerable.Range(0, items.Count() - setSize).Select(x => items.Skip(x).Take(setSize).ToList()).ToList()
The result (from C# interactive shell) looks like结果(来自 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 }
}
If you want each item to only show up once in each list, you can alter the above.如果您希望每个项目在每个列表中只显示一次,您可以更改上述内容。 Let's assume there's an odd number of elements:
假设有奇数个元素:
var items = Enumerable.Range(1, 11);
You want to change the initial range used to index into your collection.您想要更改用于索引到您的集合的初始范围。 Instead of taking 5 at a time on each index, it will jump the index up by 5 each iteration.
它不会在每个索引上一次取 5 个,而是每次迭代将索引向上跳 5 个。 The only tricky part is making sure to handle when the collection divides the number of elements you want to take;
唯一棘手的部分是确保在集合划分您想要获取的元素数量时进行处理; you don't want to end up with an empty list at the end.
你不想最后得到一个空列表。 That is, this is incorrect:
也就是说,这是不正确的:
Enumerable.Range(0, items.Count() / setSize).Select( // don't do this
The statement is then那么声明是
Enumerable.Range(0, ((items.Count() - 1) / setSize) + 1).Select(x => items.Skip(setSize * x).Take(setSize).ToList()).ToList();
The result (from C# interactive shell) looks like结果(来自 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 }
}
It looks like you want to batch elements in batches of 5 items each.看起来您想批量处理元素,每批 5 个项目。 The MoreLinq package already offers the Batch operator for this:
MoreLinq package 已经为此提供了批处理运算符:
var items=Enumerable.Range(0,17);
var batches=items.Batch(5);
foreach(var batch in batches)
{
Console.WriteLine(String.Join(" - ",batch));
}
This produces:这会产生:
0 - 1 - 2 - 3 - 4
5 - 6 - 7 - 8 - 9
10 - 11 - 12 - 13 - 14
15 - 16
This is far faster than grouping as it only iterates the collection once.这比分组要快得多,因为它只迭代一次集合。
MoreLINQ has other operators too, like Window , WindowLeft and WindowRight that produce sliding windows of values. MoreLINQ 也有其他运算符,例如Window 、 WindowLeft 和 WindowRight ,它们会产生滑动的 windows 值。
items.Window(5)
would produce: items.Window(5)
将产生:
0 - 1 - 2 - 3 - 4
1 - 2 - 3 - 4 - 5
...
11 - 12 - 13 - 14 - 15
12 - 13 - 14 - 15 - 16
The implementation实施
The operator's implementation is simple enough that you can just copy it into your project:该运算符的实现非常简单,您只需将其复制到您的项目中即可:
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);
}
}
}
The code uses arrays for efficiency.该代码使用 arrays 来提高效率。 If you really want to use mutable lists you can change the type of
bucket
to a List<T>
, eg:如果您真的想使用可变列表,您可以将
bucket
的类型更改为List<T>
,例如:
if (bucket == null)
{
bucket = new List<TSource>(size); //IMPORTANT: set the capacity to avoid reallocations
}
bucket.Add(item);
...
Why not just GroupBy
?为什么不只是
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.