【问题标题】:equivalent to a sorted dictionary that allows duplicate keys相当于允许重复键的排序字典
【发布时间】:2012-08-03 18:30:31
【问题描述】:

我需要一个数据结构,它可以按对象关联的浮点键对对象进行排序,最低优先。问题是键代表成本,所以经常有重复,我不在乎这个,因为如果两个成本相同,我会抓住第一个,因为它没有区别,问题是编译器抱怨。

是否存在行为方式相同但允许重复键的数据结构?

编辑 - 我仍然需要重复,因为如果一个结果是死胡同,我会抓住下一个(它们是 a* 搜索中的节点)

所以为了清楚起见,它需要允许按顺序排序的重复键。

【问题讨论】:

  • 如果您不关心重复项,为什么不直接删除它们?
  • 这真的很尴尬。如果没有区别,如果密钥已经存在,为什么不忽略?
  • 当您说“行为方式相同”时,您在寻找什么?字典的行为之一是,如果你给它一个键,它就会返回一个值。这只是可能的,因为您不能有重复项。
  • 将字典键映射到IEnumerable<T> 或任何你喜欢的集合怎么样?
  • 我的意思是排序字典,不是字典。已编辑。

标签: c# data-structures dictionary


【解决方案1】:

你写:

相当于允许重复键的字典

我需要一个数据结构,它可以按对象关联的浮点键对对象进行排序,最低优先。

字典不会按键对项目进行排序,因此您要查找的结构实际上根本不等同于Dictionary。你想要的是类似于 SortedListSortedDictionary 的东西,除了它应该允许重复的键。

.NET 中不存在这样的类。但是,您有几个选择:

  • 如果您想存储与某个键关联的所有值,请使用SortedDictionary<double, List<TValue>>,即使您通常只需要第一个值。第一次插入键时,创建一个新列表并将值添加到列表中。插入已存在的键时,获取列表并将值附加到列表中。
  • 您的编辑意味着此方法不适用于您的情况。使用SortedDictionary<double, TValue> 并在插入前检查重复项。只会存储每个键的第一个值,因此与上述方法不同,您无法使用此方法访问第二个值。
  • 找到一个第三方集合库,它的类可以满足您的需求。

相关

【讨论】:

  • 排序字典,而不仅仅是字典
  • @SirYakalot:是的,完全正确。查看课程:SortedDictionarySortedList。更新了答案。
【解决方案2】:

您可以创建自己的派生自 SortedSet 的类:

public class SortedTupleBag<TKey, TValue> : SortedSet<Tuple<TKey, TValue>> 
    where TKey : IComparable
{
    private class TupleComparer : Comparer<Tuple<TKey, TValue>>
    {
        public override int Compare(Tuple<TKey, TValue> x, Tuple<TKey, TValue> y)
        {
            if (x == null || y == null) return 0;

            // If the keys are the same we don't care about the order.
            // Return 1 so that duplicates are not ignored.
            return x.Item1.Equals(y.Item1)
                ? 1
                : Comparer<TKey>.Default.Compare(x.Item1, y.Item1);
        }
    }

    public SortedTupleBag() : base(new TupleComparer()) { }

    public void Add(TKey key, TValue value)
    {
        Add(new Tuple<TKey, TValue>(key, value));
    }
}

在控制台应用程序中的使用:

private static void Main(string[] args)
{
    var tuples = new SortedTupleBag<decimal, string>
    {
        {2.94M, "Item A"}, 
        {9.23M, "Item B"}, 
        {2.94M, "Item C"}, 
        {1.83M, "Item D"}
    };

    foreach (var tuple in tuples)
    {
        Console.WriteLine("{0} {1}", tuple.Item1, tuple.Item2);
    }

    Console.ReadKey();
}

产生这个结果:

 1.83 Item D
 2.94 Item A
 2.94 Item C
 9.23 Item B

【讨论】:

    【解决方案3】:

    我多次遇到这个问题,我总是使用 Wintellect (http://powercollections.codeplex.com) 的公共许可证(即免费)Power Collections。他们有一个 OrderedMultiDictionary 正是您正在寻找的。它允许重复键,并且允许您遍历所有重复的键条目。

    【讨论】:

      【解决方案4】:

      您正在寻找Lookup。 与已经提出的其他基于字典的解决方案类似,它在每个键下存储一个 IEnumerable 以处理重复项。

      var registry = Items.ToLookup(item=>item.Price);
      foreach(var item in registry[desiredPrice])
      {
           //Here you handle items that all have Price == desiredPrice
      }
      

      【讨论】:

      • Lookup 怎么不是数据结构?
      • 对不起,我的错误。我以为你在谈论ToLookup。我删除了我的反对票
      • 好的。为了清楚起见,我编辑了帖子,包括指向类型的链接。
      • 查找是否保留顺序?他似乎希望它按某种排序
      【解决方案5】:

      您可以通过覆盖 CompareTo 函数来实现。当您将 aelement 添加到 SortedDictionary 时,它使用 CompareTo(),如果结果为 0 则引发异常,但您可以更改键类实现的比较器行为以仅返回大于或小于(1 或 -1)

              public int CompareTo(int key)
          {
              if (this.key.CompareTo(key) < 1)
                  return 1;
              else
                  return -1;
          }
      

      【讨论】:

      • 这个比较方法永远不会返回 0。但是你会用一个键从字典中检索一个项目吗?
      【解决方案6】:

      您仍然可以使用字典。您只需要将值的类型更改为集合而不是单个项目:

      Dictionary<float, List<T>>
      

      字典定义不允许重复键。

      【讨论】:

        【解决方案7】:

        你说的是一个bagset 之间的区别在于集合是唯一的,而 bag 允许重复。 {a,b,c} 是一个集合; {a,b,c,a} 是一个包。

        获取C5 Collections Library 的副本。您想要课程 HashBag&lt;T&gt;TreeBag&lt;T&gt;。不同之处在于,一个中的基础数据存储是散列,另一个中是红黑树。在外部,它们的行为相同。两者都应该给你你想要的。

        【讨论】:

          【解决方案8】:

          您要查找的内容称为heappriority queue。我敢肯定,如果你用谷歌搜索,你会找到一个用于 C# 的

          【讨论】:

          • 很遗憾,C# 默认不提供内置的堆数据结构。
          • @dev27 true,但 OP 没有提到内置它的要求。
          【解决方案9】:

          您应该能够将 SortedDictionary 与 IComparer 的自定义实现一起使用以避免冲突。例如:

          private class NonCollidingFloatComparer : IComparer<float>
          {
              public int Compare(float left, float right)
              {
                  return (right > left) ? -1 : 1; // no zeroes 
              }
          }
          
          // silly method for the sake of demonstration
          public void sortNodes(List<Node> nodesToSort)
          {
              SortedDictionary<float, Node> nodesByWeight = new SortedDictionary<float, Node>(new NonCollidingFloatComparer());
              foreach (Node n in nodesToSort)
              {
                  nodesByWeight.Add(n.FloatKey, n);
              }
              foreach (Node n in nodesByWeight.Values)
              {
                  Console.WriteLine(n.FloatKey + " : " + n.UniqueID);
              }
          }
          

          【讨论】:

          • 很遗憾,您将无法使用此类比较器通过其键在字典中查找元素。
          • 发帖人要求的数据结构可以保持元素有序并允许重复;他没有表示需要按键执行查找。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-09-14
          • 1970-01-01
          • 1970-01-01
          • 2017-02-16
          • 1970-01-01
          • 2015-04-07
          • 1970-01-01
          相关资源
          最近更新 更多