[英]LINQ get x amount of elements from a list
我有一個查詢,我得到:
var query = Data.Items
.Where(x => criteria.IsMatch(x))
.ToList<Item>();
這很好。
但是,現在我想將此列表分解為x個列表,例如3個。因此,每個列表將包含查詢元素的1/3。
可以使用LINQ完成嗎?
我認為這樣可以將列表分成IGrouping
。
const int numberOfGroups = 3;
var groups = query
.Select((item, i) => new { item, i })
.GroupBy(e => e.i % numberOfGroups);
您可以使用PLINQ分區程序將結果分成單獨的枚舉。
var partitioner = Partitioner.Create<Item>(query);
var partitions = partitioner.GetPartitions(3);
您需要引用System.Collections.Concurrent命名空間。 partitions
將是IEnumerable<Item>
的列表,其中每個可枚舉都返回查詢的一部分。
您可以創建擴展方法:
public static IList<List<T>> GetChunks<T>(this IList<T> items, int numOfChunks)
{
if (items.Count < numOfChunks)
throw new ArgumentException("The number of elements is lower than the number of chunks");
int div = items.Count / numOfChunks;
int rem = items.Count % numOfChunks;
var listOfLists = new List<T>[numOfChunks];
for (int i = 0; i < numOfChunks; i++)
listOfLists[i] = new List<T>();
int currentGrp = 0;
int currRemainder = rem;
foreach (var el in items)
{
int currentElementsInGrp = listOfLists[currentGrp].Count;
if (currentElementsInGrp == div && currRemainder > 0)
{
currRemainder--;
}
else if (currentElementsInGrp >= div)
{
currentGrp++;
}
listOfLists[currentGrp].Add(el);
}
return listOfLists;
}
然后像這樣使用它:
var chunks = query.GetChunks(3);
NB
如果元素的數量不能被組的數量整除,則第一個組將更大。 例如[0,1,2,3,4] --> [0,1] - [2,3] - [4]
您可以使用Skip
和Take
在一個簡單for
完成你想要什么
var groupSize = (int)Math.Ceiling(query.Count() / 3d);
var result = new List<List<Item>>();
for (var j = 0; j < 3; j++)
result.Add(query.Skip(j * groupSize).Take(groupSize).ToList());
如果按照Daniel Imms的建議使用IGrouping
元素的順序無關緊要,則可能是最優雅的方法(添加.Select(gr => gr.Select(e => e.item))
以獲得IEnumerable<IEnumerable<T>>
)。
但是,如果要保留順序,則需要知道元素總數。 否則,您將不知道何時開始下一個小組。 您可以使用LINQ進行此操作,但它需要兩個枚舉:一個用於計數,另一個用於返回數據(如Esteban Elverdin所建議)。
如果枚舉查詢很昂貴,則可以通過將查詢轉換為列表然后使用GetRange
方法來避免第二次枚舉:
public static IEnumerable<List<T>> SplitList<T>(List<T> list, int numberOfRanges)
{
int sizeOfRanges = list.Count / numberOfRanges;
int remainder = list.Count % numberOfRanges;
int startIndex = 0;
for (int i = 0; i < numberOfRanges; i++)
{
int size = sizeOfRanges + (remainder > 0 ? 1 : 0);
yield return list.GetRange(startIndex, size);
if (remainder > 0)
{
remainder--;
}
startIndex += size;
}
}
static void Main()
{
List<int> list = Enumerable.Range(0, 10).ToList();
IEnumerable<List<int>> result = SplitList(list, 3);
foreach (List<int> values in result)
{
string s = string.Join(", ", values);
Console.WriteLine("{{ {0} }}", s);
}
}
輸出為:
{ 0, 1, 2, 3 }
{ 4, 5, 6 }
{ 7, 8, 9 }
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.