字典中的每个键都有 MANY 整数列表。我需要遍历每个键,每次从列表中取出n个项目,直到我遍历所有列表中的所有项目。实施它的最佳方法是什么?我需要实现一些枚举器吗?
代码:
enum ItemType { Type1=1, Type2=2, Type3=3 };
var items = new Dictionary<ItemType, List<int>>();
items[ItemType.Type1] = new List<int> { 1, 2, 3, 4, 5 };
items[ItemType.Type2] = new List<int> { 11, 12, 13, 15 };
items[ItemType.Type3] = new List<int> { 21, 22, 23, 24, 25, 26 };
例如:n = 2。
已更新: 最后,我必须按顺序获得这些项目的清单:1,2,11,12,21,22,3,4,13,15,23,24,5,25,26
答案 0 :(得分:1)
以下是如何做到的:
enum ItemType { Type1 = 1, Type2 = 2, Type3 = 3 };
Dictionary<ItemType, List<int>> items = new Dictionary<ItemType, List<int>>();
items[ItemType.Type1] = new List<int> { 1, 2, 3, 4, 5 };
items[ItemType.Type2] = new List<int> { 11, 12, 13, 15 };
items[ItemType.Type3] = new List<int> { 21, 22, 23, 24, 25, 26 };
// Define upper boundary of iteration
int max = items.Values.Select(v => v.Count).Max();
int i = 0, n = 2;
while (i + n <= max)
{
// Skip and Take - to select only next portion of elements, SelectMany - to merge resulting lists of portions
List<int> res = items.Values.Select(v => v.Skip(i).Take(n)).SelectMany(v => v).ToList();
i += n;
// Further processing of res
}
答案 1 :(得分:0)
这将为你做到:
var resultList = new List<int>();
items.ToList().ForEach(listInts => resultList.AddRange(listInts.Take(n));
这让LINQ扩展为您付出了艰苦的努力。 Take()会尽可能多地使用ForEach(),如果您请求的内容超过了它,则不会抛出异常。在这种情况下,我将结果添加到另一个列表中,但您可以轻松标记Take()
末尾的另一个{{3}},以便迭代结果。
我从示例序列中注意到您正在从 x 起点重新检索 n 项目数 - 如果您编辑问题以包括如何决定起点我会调整我的例子。
因为你希望每次迭代都从每个列表中获取 n 个项目,直到没有更多的元素返回,这样就可以了:
class Program
{
static void Main(string[] args)
{
var items = new Dictionary<ItemType, List<int>>();
items[ItemType.Type1] = new List<int> { 1, 2, 3, 4, 5 };
items[ItemType.Type2] = new List<int> { 11, 12, 13, 15 };
items[ItemType.Type3] = new List<int> { 21, 22, 23, 24, 25, 26 };
int numItemsTaken = 0;
var resultsList = new List<int>();
int n = 2, startpoint = 0, previousListSize = 0;
do
{
items.ToList().ForEach(x => resultsList.AddRange(x.Value.Skip(startpoint).Take(n)));
startpoint += n;
numItemsTaken = resultsList.Count - previousListSize;
previousListSize = resultsList.Count;
}
while (numItemsTaken > 0);
Console.WriteLine(string.Join(", ", resultsList));
Console.ReadKey();
}
enum ItemType { Type1 = 1, Type2 = 2, Type3 = 3 };
}
这是您使用do while
循环的少数几次之一,无论n
的大小或列表的大小或有多少列表,它都会有效。< / p>
答案 2 :(得分:0)
您不需要定义自定义枚举器,只需手动使用MoveNext
:
第1步,将Dictionary<ItemType, List<int>>
转换为Dictionary<ItemType, List<IEnumerator<int>>
:
var iterators = items.ToDictionary(p => p.Key, p => (IEnumerator<int>)p.Value.GetEnumerator());
第2步:手动处理MoveNext
:
public List<int> Get(Dictionary<ItemType, IEnumerator<int>> iterators, int n)
{
var result = new List<int>();
foreach (var itor in iterators.Values)
{
for (var i = 0; i < n && itor.MoveNext(); i++)
{
result.Add(itor.Current);
}
}
return result;
}
多次调用Get
会给您预期的结果。调查员本身将保持当前的位置。
答案 3 :(得分:0)
“最佳方式”取决于您的目标,例如:可读性或性能。
这是一种方式:
var firstIter = items.Values.SelectMany(list => list.Take(2));
var secondIter = items.Values.SelectMany(list => list.Skip(2).Take(2));
var thirdIter = items.Values.SelectMany(list => list.Skip(4).Take(2));
var finalResult = firstIter.Concat(secondIter).Concat(thirdIter);
编辑:这是一个更通用的版本:
var finalResult = Flatten(items, 0, 2);
IEnumerable<int> Flatten(
Dictionary<ItemType, List<int>> items,
int skipCount,
int takeCount)
{
var iter = items.Values.SelectMany(list => list.Skip(skipCount).Take(takeCount));
return
iter.Count() == 0 ? // a bit inefficient here
iter :
iter.Concat(Flatten(items, skipCount + takeCount, takeCount));
}