【问题标题】:Serially assign values to OrderedDictionary in C#在 C# 中为 OrderedDictionary 串行赋值
【发布时间】:2016-02-04 16:44:30
【问题描述】:

我有两个键值对,现在我想用较小的键值对以串行方式填充较大的键值对。

  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 的值以重复的方式填充这些空值。

【问题讨论】:

  • 100、109、13、23部分从何而来?恐怕我觉得您的问题很难理解...请编辑它以使其更清楚很多
  • 你想知道如何在 c# 中做 sql join 之类的事情吗?
  • @AntiHeadshot 这不是 sql 而是 c#
  • 所以听起来你需要一个 list 选择器,然后有一个嵌套循环来填充 pickersToTicketMap...
  • 是的@JonSkeet,这正是我想要的,以这种方式。 44, 543, 下一个选择器, ..... 最后一个选择器, 44, 543 ......

标签: c# ordereddictionary


【解决方案1】:

听起来您应该从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() 返回的迭代器不需要处理。

【讨论】:

  • @TimSchmelter:是的 - 我投票决定关闭,因为它最初非常不清楚。然后澄清到我可以回答的程度,然后其他一些人认为它仍然太不清楚而无法回答。已投票决定现在重新开放。
  • 这一行 ticketToPickerMap[ticket] = pickerIterator.Current 没有返回值“System.Collections.DictionaryEntry”而不是选择器编号
  • @Edwin:你确定你有完全我的代码,var pickers = pickersPool.Values;?我故意只迭代 values 集合,not pickersPool.
【解决方案2】:

可能有你要找的东西:

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

【讨论】:

  • 您介意解释一下您的代码究竟做了什么吗?
  • @CodeCaster 补充说明
【解决方案3】:

所以你想用可能较小的字典中的连续和重复值来更新大字典的值?我想到了两种方法,一种更简单:

  1. 您可以使用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];
    
  2. 我更喜欢上述方法,因为它比我使用“无限”序列的第二种方法更具可读性。这是扩展方法:

    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&lt;string&gt;().ToList() 很重要,因为我不能使用原始的Keys 集合。如果在枚举过程中更改它,则会出现异常。

【讨论】:

    【解决方案4】:

    感谢@jon skeet,尽管他在尝试为此提供破解时对我的对象进行了太多修改。

    查看您的解决方案后,我实现了以下内容,它适用于我的所有对象。

    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();
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-11
      • 2016-02-09
      • 2011-09-08
      • 1970-01-01
      • 2018-06-11
      • 1970-01-01
      • 2010-09-21
      相关资源
      最近更新 更多