在 C# 中为 OrderedDictionary 连续赋值
Serially assign values to OrderedDictionary in C#
我有两个键值对,现在我想用较小的值依次填充较大的键值对。
OrderedDictionary pickersPool = new OrderedDictionary(); // Small
OrderedDictionary pickersToTicketMap = new OrderedDictionary(); // Big
pickersPool.Add("emp1", 44);
pickersPool.Add("emp2", 543);
现在我需要将 pickersToTicketMap 更新为如下所示:
("100", 44);
("109", 543);
("13", 44);
("23", 543);
所以基本上我需要 pickersPool 值来循环遍历 pickersToTicketMap 字典的键。
我需要 pickerPool 值来保持循环 pickersToTicketMap 并连续更新它的值。
pickersToTicketMap 有序列表的初始值为:
("100", "null");
("109", "null");
("13", "null");
("23", "null");
所以我需要 PickerPool orderedDictionary 的值以重复的方式填充这些空值。
可能有您要找的:
using System.Linq;
...
int i = 0;
// Cast OrderedDictionary to IEnumarable<DictionaryEntry> to be able to use System.Linq
object[] keys = pickersToTicketMap.Cast<DictionaryEntry>().Select(x=>x.Key).ToArray();
IEnumerable<DictionaryEntry> pickersPoolEnumerable = pickersPool.Cast<DictionaryEntry>();
// iterate over all keys (sorted)
foreach (object key in keys)
{
// Set the value of key to element i % pickerPool.Count
// i % pickerPool.Count will return for Count = 2
// 0, 1, 0, 1, 0, ...
pickersToTicketMap[key] = pickersPoolEnumarable
.ElementAt(i % pickersPool.Count).Value;
i++;
}
PS:ToArray()
需要单独的键副本,因此您不会因为更改要迭代的元素而得到 InvalidOperationException
。
听起来你应该从 List<string>
(或者可能是 List<int>
开始,因为它们似乎都是整数......)而不是用空条目填充你的地图来开始和。所以像这样:
List<string> tickets = new List<string> { "100", "109", "13", "23" };
然后您可以将 pickersToTicketMap
填充为:
var pickers = pickersPool.Values;
var pickerIterator = pickers.GetEnumerator();
foreach (var ticket in tickets)
{
if (!pickerIterator.MoveNext())
{
// Start the next picker...
pickerIterator = pickers.GetEnumerator();
if (!pickerIterator.MoveNext())
{
throw new InvalidOperationException("No pickers available!");
}
}
ticketToPickerMap[ticket] = pickerIterator.Current;
}
请注意,我已将名称从 pickersToTicketMap
更改为 ticketToPickerMap
,因为这似乎是您真正的意思 - 键是票,值是选择器。
另请注意,我 不是 处理来自 pickers
的迭代器。这通常是个坏主意,但在这种情况下,我假设 OrderedDictionary.Values.GetEnumerator()
返回的迭代器不需要处理。
所以你想用可能较小的字典中的连续和重复的值来更新大字典的值?我有两种方法,一种更简单:
您可以使用 Enumerable.Repeat
重复较小的集合。你必须计算计数。然后您可以使用 SelectMany
将其展平并使用 ToList
创建一个集合。然后你可以使用 for
循环通过索引用列表中的值更新更大的字典:
IEnumerable<int> values = pickersPool.Values.Cast<int>();
if (pickersPool.Count < pickersToTicketMap.Count)
{
// Repeat this collection until it has the same size as the larger collection
values = Enumerable.Repeat( values,
pickersToTicketMap.Count / pickersPool.Count
+ pickersToTicketMap.Count % pickersPool.Count
)
.SelectMany(intColl => intColl);
}
List<int> valueList = values.ToList();
for (int i = 0; i < valueList.Count; i++)
pickersToTicketMap[i] = valueList[i];
我更喜欢上面的方法,因为它比我的第二个使用 "infinite" 序列的方法更具可读性。这是扩展方法:
public static IEnumerable<T> RepeatEndless<T>(this IEnumerable<T> sequence)
{
while (true)
foreach (var item in sequence)
yield return item;
}
现在您可以使用此代码更新较大字典的值:
var endlessPickersPool = pickersPool.Cast<DictionaryEntry>().RepeatEndless();
IEnumerator<DictionaryEntry> endlessEnumerator;
IEnumerator<string> ptmKeyEnumerator;
using ((endlessEnumerator = endlessPickersPool.GetEnumerator()) as IDisposable)
using ((ptmKeyEnumerator = pickersToTicketMap.Keys.Cast<string>().ToList().GetEnumerator()) as IDisposable)
{
while (endlessEnumerator.MoveNext() && ptmKeyEnumerator.MoveNext())
{
DictionaryEntry pickersPoolItem = (DictionaryEntry)endlessEnumerator.Current;
pickersToTicketMap[ptmKeyEnumerator.Current] = pickersPoolItem.Value;
}
}
请注意,我使用 largerDict.Keys.Cast<string>().ToList()
很重要,因为我无法使用原始的 Keys
集合。如果在枚举期间更改它,则会出现异常。
感谢@jon skeet,虽然他在尝试为此提供 hack 时修改了我的对象太多。
在查看了您的解决方案后,我实施了以下方法,它适用于我所有的对象。
var pickerIterator = pickerPool.GetEnumerator();
foreach (DictionaryEntry ticket in tickets)
{
if (!pickerIterator.MoveNext())
{
// Start the next picker...
pickerIterator = pickerPool.GetEnumerator();
if (!pickerIterator.MoveNext())
{
throw new InvalidOperationException("No pickers available!");
}
}
ticketToPickerMap[ticket.Key] = pickerIterator.Value.ToString();
}
我有两个键值对,现在我想用较小的值依次填充较大的键值对。
OrderedDictionary pickersPool = new OrderedDictionary(); // Small
OrderedDictionary pickersToTicketMap = new OrderedDictionary(); // Big
pickersPool.Add("emp1", 44);
pickersPool.Add("emp2", 543);
现在我需要将 pickersToTicketMap 更新为如下所示:
("100", 44);
("109", 543);
("13", 44);
("23", 543);
所以基本上我需要 pickersPool 值来循环遍历 pickersToTicketMap 字典的键。
我需要 pickerPool 值来保持循环 pickersToTicketMap 并连续更新它的值。
pickersToTicketMap 有序列表的初始值为:
("100", "null");
("109", "null");
("13", "null");
("23", "null");
所以我需要 PickerPool orderedDictionary 的值以重复的方式填充这些空值。
可能有您要找的:
using System.Linq;
...
int i = 0;
// Cast OrderedDictionary to IEnumarable<DictionaryEntry> to be able to use System.Linq
object[] keys = pickersToTicketMap.Cast<DictionaryEntry>().Select(x=>x.Key).ToArray();
IEnumerable<DictionaryEntry> pickersPoolEnumerable = pickersPool.Cast<DictionaryEntry>();
// iterate over all keys (sorted)
foreach (object key in keys)
{
// Set the value of key to element i % pickerPool.Count
// i % pickerPool.Count will return for Count = 2
// 0, 1, 0, 1, 0, ...
pickersToTicketMap[key] = pickersPoolEnumarable
.ElementAt(i % pickersPool.Count).Value;
i++;
}
PS:ToArray()
需要单独的键副本,因此您不会因为更改要迭代的元素而得到 InvalidOperationException
。
听起来你应该从 List<string>
(或者可能是 List<int>
开始,因为它们似乎都是整数......)而不是用空条目填充你的地图来开始和。所以像这样:
List<string> tickets = new List<string> { "100", "109", "13", "23" };
然后您可以将 pickersToTicketMap
填充为:
var pickers = pickersPool.Values;
var pickerIterator = pickers.GetEnumerator();
foreach (var ticket in tickets)
{
if (!pickerIterator.MoveNext())
{
// Start the next picker...
pickerIterator = pickers.GetEnumerator();
if (!pickerIterator.MoveNext())
{
throw new InvalidOperationException("No pickers available!");
}
}
ticketToPickerMap[ticket] = pickerIterator.Current;
}
请注意,我已将名称从 pickersToTicketMap
更改为 ticketToPickerMap
,因为这似乎是您真正的意思 - 键是票,值是选择器。
另请注意,我 不是 处理来自 pickers
的迭代器。这通常是个坏主意,但在这种情况下,我假设 OrderedDictionary.Values.GetEnumerator()
返回的迭代器不需要处理。
所以你想用可能较小的字典中的连续和重复的值来更新大字典的值?我有两种方法,一种更简单:
您可以使用
Enumerable.Repeat
重复较小的集合。你必须计算计数。然后您可以使用SelectMany
将其展平并使用ToList
创建一个集合。然后你可以使用for
循环通过索引用列表中的值更新更大的字典:IEnumerable<int> values = pickersPool.Values.Cast<int>(); if (pickersPool.Count < pickersToTicketMap.Count) { // Repeat this collection until it has the same size as the larger collection values = Enumerable.Repeat( values, pickersToTicketMap.Count / pickersPool.Count + pickersToTicketMap.Count % pickersPool.Count ) .SelectMany(intColl => intColl); } List<int> valueList = values.ToList(); for (int i = 0; i < valueList.Count; i++) pickersToTicketMap[i] = valueList[i];
我更喜欢上面的方法,因为它比我的第二个使用 "infinite" 序列的方法更具可读性。这是扩展方法:
public static IEnumerable<T> RepeatEndless<T>(this IEnumerable<T> sequence) { while (true) foreach (var item in sequence) yield return item; }
现在您可以使用此代码更新较大字典的值:
var endlessPickersPool = pickersPool.Cast<DictionaryEntry>().RepeatEndless();
IEnumerator<DictionaryEntry> endlessEnumerator;
IEnumerator<string> ptmKeyEnumerator;
using ((endlessEnumerator = endlessPickersPool.GetEnumerator()) as IDisposable)
using ((ptmKeyEnumerator = pickersToTicketMap.Keys.Cast<string>().ToList().GetEnumerator()) as IDisposable)
{
while (endlessEnumerator.MoveNext() && ptmKeyEnumerator.MoveNext())
{
DictionaryEntry pickersPoolItem = (DictionaryEntry)endlessEnumerator.Current;
pickersToTicketMap[ptmKeyEnumerator.Current] = pickersPoolItem.Value;
}
}
请注意,我使用 largerDict.Keys.Cast<string>().ToList()
很重要,因为我无法使用原始的 Keys
集合。如果在枚举期间更改它,则会出现异常。
感谢@jon skeet,虽然他在尝试为此提供 hack 时修改了我的对象太多。
在查看了您的解决方案后,我实施了以下方法,它适用于我所有的对象。
var pickerIterator = pickerPool.GetEnumerator();
foreach (DictionaryEntry ticket in tickets)
{
if (!pickerIterator.MoveNext())
{
// Start the next picker...
pickerIterator = pickerPool.GetEnumerator();
if (!pickerIterator.MoveNext())
{
throw new InvalidOperationException("No pickers available!");
}
}
ticketToPickerMap[ticket.Key] = pickerIterator.Value.ToString();
}