是否有任何方法可以将List<SomeObject>分离为SomeObject的几个单独的列表,使用项目索引作为每个分割的分隔符?
让我举个例子:
我有一个List<SomeObject>,我需要一个List<List<SomeObject>>或List<SomeObject>[],这样每个结果列表将包含一组原始列表的3个项目(依次)。
eg.:
原始列表:[a, g, e, w, p, s, q, f, x, y, i, m, c]
结果列表:[a、g e], [w、p, s], [q, f, x]、[y,我,m], [c]
我还需要结果列表的大小是这个函数的参数。
看看这个!我有一个序列计数器和日期的元素列表。每次序列重新启动时,我都想创建一个新列表。
例:消息列表。
List<dynamic> messages = new List<dynamic>
{
new { FcntUp = 101, CommTimestamp = "2019-01-01 00:00:01" },
new { FcntUp = 102, CommTimestamp = "2019-01-01 00:00:02" },
new { FcntUp = 103, CommTimestamp = "2019-01-01 00:00:03" },
//restart of sequence
new { FcntUp = 1, CommTimestamp = "2019-01-01 00:00:04" },
new { FcntUp = 2, CommTimestamp = "2019-01-01 00:00:05" },
new { FcntUp = 3, CommTimestamp = "2019-01-01 00:00:06" },
//restart of sequence
new { FcntUp = 1, CommTimestamp = "2019-01-01 00:00:07" },
new { FcntUp = 2, CommTimestamp = "2019-01-01 00:00:08" },
new { FcntUp = 3, CommTimestamp = "2019-01-01 00:00:09" }
};
我想在计数器重新启动时将列表拆分为单独的列表。代码如下:
var arraylist = new List<List<dynamic>>();
List<dynamic> messages = new List<dynamic>
{
new { FcntUp = 101, CommTimestamp = "2019-01-01 00:00:01" },
new { FcntUp = 102, CommTimestamp = "2019-01-01 00:00:02" },
new { FcntUp = 103, CommTimestamp = "2019-01-01 00:00:03" },
//restart of sequence
new { FcntUp = 1, CommTimestamp = "2019-01-01 00:00:04" },
new { FcntUp = 2, CommTimestamp = "2019-01-01 00:00:05" },
new { FcntUp = 3, CommTimestamp = "2019-01-01 00:00:06" },
//restart of sequence
new { FcntUp = 1, CommTimestamp = "2019-01-01 00:00:07" },
new { FcntUp = 2, CommTimestamp = "2019-01-01 00:00:08" },
new { FcntUp = 3, CommTimestamp = "2019-01-01 00:00:09" }
};
//group by FcntUp and CommTimestamp
var query = messages.GroupBy(x => new { x.FcntUp, x.CommTimestamp });
//declare the current item
dynamic currentItem = null;
//declare the list of ranges
List<dynamic> range = null;
//loop through the sorted list
foreach (var item in query)
{
//check if start of new range
if (currentItem == null || item.Key.FcntUp < currentItem.Key.FcntUp)
{
//create a new list if the FcntUp starts on a new range
range = new List<dynamic>();
//add the list to the parent list
arraylist.Add(range);
}
//add the item to the sublist
range.Add(item);
//set the current item
currentItem = item;
}
我将主要答案设置为IOC容器,以确定在哪里进行分割。(在阅读这篇文章的同时寻找答案,谁真的只想在3个项目上进行拆分?)
这种方法允许人们根据需要对任何类型的项目进行拆分。
public static List<List<T>> SplitOn<T>(List<T> main, Func<T, bool> splitOn)
{
int groupIndex = 0;
return main.Select( item => new
{
Group = (splitOn.Invoke(item) ? ++groupIndex : groupIndex),
Value = item
})
.GroupBy( it2 => it2.Group)
.Select(x => x.Select(v => v.Value).ToList())
.ToList();
}
所以OP的代码是
var it = new List<string>()
{ "a", "g", "e", "w", "p", "s", "q", "f", "x", "y", "i", "m", "c" };
int index = 0;
var result = SplitOn(it, (itm) => (index++ % 3) == 0 );
如果源集合实现了IList < T >(按索引随机访问),我们可以使用下面的方法。它只在真正访问元素时获取元素,因此这对于延迟求值的集合特别有用。类似于unbounded IEnumerable< T >,但是对于IList< T >。
public static IEnumerable<IEnumerable<T>> Chunkify<T>(this IList<T> src, int chunkSize)
{
if (src == null) throw new ArgumentNullException(nameof(src));
if (chunkSize < 1) throw new ArgumentOutOfRangeException(nameof(chunkSize), $"must be > 0, got {chunkSize}");
for(var ci = 0; ci <= src.Count/chunkSize; ci++){
yield return Window(src, ci*chunkSize, Math.Min((ci+1)*chunkSize, src.Count)-1);
}
}
private static IEnumerable<T> Window<T>(IList<T> src, int startIdx, int endIdx)
{
Console.WriteLine($"window {startIdx} - {endIdx}");
while(startIdx <= endIdx){
yield return src[startIdx++];
}
}