如何遍历字典>每次返回每个列表的部分值
本文关键字:返回 列表 List 遍历 何遍历 字典 MyEnum int | 更新日期: 2023-09-27 18:36:30
字典中的每个键都有许多整数的列表。我需要遍历每个键,每次从列表中获取 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
已更新:最后,我必须按以下顺序获取此项目的列表:1,2,11,12,21,22,3,4,13,15,23,24,5,25,26
以下是完成它的方法:
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
}
无需
定义自定义枚举器,只需手动使用该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
将给你预期的结果。枚举器本身将保持当前位置。
这将为您完成:
var resultList = new List<int>();
items.ToList().ForEach(listInts => resultList.AddRange(listInts.Take(n));
这让 LINQ 扩展为您完成艰苦的工作。Take() 将尽可能多地获取,而不会引发异常,如果您请求的比请求的多。在这种情况下,我将结果添加到另一个列表中,但您也可以轻松地在Take()
末尾标记另一个 ForEach() 以迭代结果。
我从示例序列中注意到您正在从 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
的大小、列表的大小或列表的数量如何,它都可以工作。
"最佳方法"取决于您的目标,例如可读性或性能。
这是一种方法:
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));
}