【问题标题】:How do I get the nth element from a Dictionary?如何从字典中获取第 n 个元素?
【发布时间】:2023-03-08 14:42:01
【问题描述】:
cipher = new Dictionary<char,int>;
cipher.Add( 'a', 324 );
cipher.Add( 'b', 553 );
cipher.Add( 'c', 915 );

如何获得第二个元素?例如,我想要这样的东西:

KeyValuePair pair = cipher[1]

其中pair包含( 'b', 553 )


根据合作社使用列表的建议,一切正常:

List<KeyValuePair<char, int>> cipher = new List<KeyValuePair<char, int>>();
cipher.Add( new KeyValuePair<char, int>( 'a', 324 ) );
cipher.Add( new KeyValuePair<char, int>( 'b', 553 ) );
cipher.Add( new KeyValuePair<char, int>( 'c', 915 ) );

KeyValuePair<char, int> pair = cipher[ 1 ];

假设我是正确的,项目按添加顺序保留在列表中,我相信我可以只使用List,而不是建议的SortedList。

【问题讨论】:

  • 对于那些阅读这个问题的人,我强烈质疑您是否需要按索引访问字典中的元素。值得检查您的范例。同理,不需要 DataReader 的第 5 条记录。您可能只需要枚举这些项目。如果不是 foreach,则使用 Dictionary.GetEnumerator() 的 MoveNext() 和 Current。否则使用不同的、可索引的集合对象,如 SortedDictionary 或数组。有时这个 Q 会被来自其他语言但没有 foreach 功能的编码人员询问,因此有一个适应阶段。

标签: c# dictionary


【解决方案1】:

这是一个老问题,但对我很有帮助。这是我使用的一个实现。我希望第 n 个元素基于插入顺序。

public class IndexedDictionary<TKey, TValue> : IEnumerable<TValue> {
  private List<TValue> list = new List<TValue>();
  private Dictionary<TKey, TValue> dict = new Dictionary<TKey, TValue>();

  public TValue this[int index] { get { return list[index]; } }
  public TValue this[TKey key] { get { return dict[key]; } }

  public Dictionary<TKey, TValue>.KeyCollection Keys { get { return dict.Keys; } }

  public int Count { get { return list.Count; } }

  public int IndexOf(TValue item) { return list.IndexOf(item);  }
  public int IndexOfKey(TKey key) { return list.IndexOf(dict[key]); } 

  public void Add(TKey key, TValue value) {
    list.Add(value);
    dict.Add(key, value);
  }

  IEnumerator<TValue> IEnumerable<TValue>.GetEnumerator() {
    return list.GetEnumerator();
  }

  IEnumerator IEnumerable.GetEnumerator() {
    return list.GetEnumerator();
  }
}

【讨论】:

    【解决方案2】:

    你可以像这样使用ElementAt():

    cipher.ElementAt(index);
    

    它比Select 选项更好,因为这样您就不必遍历字典:

    文档

    /// <summary>Returns the element at a specified index in a sequence.</summary>
    /// <returns>The element at the specified position in the source sequence.</returns>
    /// <param name="source">An <see cref="T:System.Collections.Generic.IEnumerable`1" /> to return an element from.</param>
    /// <param name="index">The zero-based index of the element to retrieve.</param>
    /// <typeparam name="TSource">The type of the elements of <paramref name="source" />.</typeparam>
    /// <exception cref="T:System.ArgumentNullException">
    /// <paramref name="source" /> is null.</exception>
    /// <exception cref="T:System.ArgumentOutOfRangeException">
    /// <paramref name="index" /> is less than 0 or greater than or equal to the number of elements in <paramref name="source" />.</exception>
    

    【讨论】:

    • 你能解释一下为什么这是一个比其他人发布的更好的答案吗?以后可以帮到别人!
    • @wahwahwah 调用 ElementAt 利用 Dictionary 类的内置功能来检索元素。其他方法要么依赖于遍历 IEnumerable,要么依赖于创建一个包含所有元素的全新 List 来获取一个。
    【解决方案3】:

    您可以在您的“密码”Dictionary 上应用以下 LINQ 查询

            var cipher = new Dictionary<char, int>();
            cipher.Add('a', 324);
            cipher.Add('b', 553);
            cipher.Add('c', 915);
    
            var nThValue = cipher.Select((Val, Index) => new { Val, Index })
                .Single(viPair => viPair.Index == 1)   //Selecting dictionary item with it's index using index
                .Val                                   //Extracting KeyValuePair from dictionary item
                .Value;                                //Extracting Value from KeyValuePair
    

    【讨论】:

      【解决方案4】:

      这里有人问了这个问题:How to retrieve Nth item in dictionary?。它应该很快就会关闭,但我注意到这里的答案缺少新的 OrderedDictionary 类。

      现在(从 .NET 4 开始)有一个 OrderedDictionary 类。这允许在提供排序的同时进行快速查找。 Item(Int32) 方法返回第 n 个元素。

      【讨论】:

        【解决方案5】:

        像这样:

        int n = 0;
        int nthValue = cipher[cipher.Keys.ToList()[n]];
        

        请注意,您还需要在页面顶部引用 Linq...

        using System.Linq;
        

        【讨论】:

        • 我认为虽然目前这可能有效,但值得注意的是它可能并不总是有效。如果我错了手榴弹,请纠正我,但MSDN says“Dictionary&lt;TKey, TValue&gt;.KeyCollection 中的键顺序未指定”。这意味着无法保证此集合中的顺序将保持一致。类似地,遍历字典MSDN says“返回项目的顺序未定义”。
        • 如果可以,最好使用新的Ordered Dictionary。
        • 你是绝对正确的本。然而,这是我在 2009 年写它时实用的方法之一,它现在在 2016 年仍然有效。有很多比我更聪明的人会解释为什么这种方法不应该工作和不应该工作的所有充分理由不被使用。请随时研究所有这些回复并了解所有相关信息。或者,您可以直接粘贴这段代码,看着它神奇地按照我所说的那样做,然后回到您的生活中做一些很棒的事情。
        • @grenade 非常感谢您的代码和精美的散文,我很遗憾地说您的方法在与 MSDN 的战斗中失败了——至少在 ConcurrentDictionary 方面是这样。正如 Ben 所观察到的那样,物品返回的顺序是不确定的。
        【解决方案6】:

        你真的需要用钥匙查找吗?如果没有,请使用 List&lt;KeyValuePair&lt;char, int&gt;&gt;(或者更好的是,创建一个类型来封装 char 和 int)。

        字典本身并没有排序 - 在 .NET 中 排序的字典实现是按键排序的,而不是按插入顺序。

        如果您需要通过插入顺序和键访问集合,我建议将 List 和 Dictionary 封装在一个集合类型中。

        或者,如果列表会很短,则允许通过执行线性搜索来按索引查找...

        【讨论】:

        • 我来这个问题是因为我试图在一个控件上实现可访问性,该控件使用字典作为它需要绘制的项目的集合。所以控件实际上确实需要通过键查找项目,但我还需要能够按索引查找项目以覆盖AccessibleObject.GetChild(index As Integer)。
        • 也许现在已经过去了 5 年,我终于可以承认,我投下反对票纯粹是为了让我的答案看起来比你的得分更高,这是公然试图抢夺代表。在我的辩护中,我是 SO 的新手,也很挑剔。所以当投票变老时,也不会让人们纠正他们的错误,所以我忍受着我的耻辱。
        • @grenade,我刚刚注意到你发自内心的认罪!我不知道乔恩是否注意到了这一点,但为了你的荣誉(而不是他需要另外 10 个代表点),我现在已经投票支持他的回答以帮助补偿你的反对票。同时,通过这样做,我现在进一步降低了自己在某个问题的答案上获得比 Jon Skeet 更多赞成票的希望!
        【解决方案7】:

        为了坚持你原来的字典规范,我抛出了一些代码并想出了:

        Dictionary<string, string> d = new Dictionary<string, string>();
        
        d.Add("a", "apple");
        d.Add("b", "ball");
        d.Add("c", "cat");
        d.Add("d", "dog");
        
        int t = 0;
        foreach (string s in d.Values)
        {
            t++;
            if (t == 2) Console.WriteLine(s);
        }
        

        它似乎确实将第二个项目(“球”)重复写入控制台。如果将它包装到方法调用中以获取第 n 个元素,它可能会起作用。不过,这很丑陋。如果你可以像@thecoop 建议的那样做一个 SortedList,你会更好。

        【讨论】:

          【解决方案8】:

          问题是字典没有排序。你想要的是一个SortedList,它允许你通过索引和键来获取值,尽管你可能需要在构造函数中指定你自己的比较器来获得你想要的排序。然后,您可以访问键和值的有序列表,并根据需要使用 IndexOfKey/IndexOfValue 方法的各种组合。

          【讨论】:

          • 您可以使用ElementAt(int) 扩展方法,但就像thecoop 所说,它没有顺序,因此甚至不能保证两次连续调用之间的结果相同。
          • 字典是否排序无关紧要,您只需要保证第n个键将一致地返回第n个值并且确实如此。请参阅下面的答案。
          • @Gavimoss:不。 Keys 和 Values 属性返回 IList&lt;T&gt;
          • 如果使用排序列表,更简单的方法是使用Cipher.GetKey(n) 作为第n 个键,使用Cipher.GetByIndex(n) 作为第n 个值。
          猜你喜欢
          • 1970-01-01
          • 2012-12-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多