equivalent to a sorted dictionary that allows duplicate keys

蓝咒 提交于 2021-02-18 20:15:16

问题


I need a data structure that can sort objects by the float keys they're associated with, lowest first. The trouble is that the keys represent cost so there are often duplicates, I don't care about this because if two have the same cost I'll just grab the first as it makes no difference, the problem is that the compiler complains.

Is there a data structure that behaves in the same way but allows duplicate keys?

EDIT - I still need the duplicates though because if one turns out to be a dead-end, I grab the next (they're nodes in an a* search)

so just to be clear, it needs to allow duplicate keys that are sorted in order.


回答1:


You write:

equivalent to a dictionary that allows duplicate keys

I need a data structure that can sort objects by the float keys they're associated with, lowest first.

A dictionary does not keep the items sorted by the keys, so the structure you are looking for is actually not equivalent to a Dictionary at all. What you want is something similar to a SortedList or SortedDictionary except that it should allow duplicate keys.

No such class exists in .NET. However you have a few options:

  • Use SortedDictionary<double, List<TValue>> if you want to store all the values associated for a key, even though you usually only need the first. When inserting a key for the first time, create a new list and add the value to the list. When inserting a key that already exists, fetch the list and append the value to the list.
  • Your edit means that this approach does not apply to your situation.Use SortedDictionary<double, TValue> and check for duplicates before inserting. Only the first value for each key will be stored, so unlike the above approach, you can't access the second value at all with this method.
  • Find a third party collections library that has a class that does what you want.

Related

  • What's the difference between SortedList and SortedDictionary?



回答2:


You could create your own class that derives from 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));
    }
}

Usage in a console app:

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

produces this result:

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



回答3:


I've hit this problem a number of times, and I always use the public license (i.e. free) Power Collections from Wintellect (http://powercollections.codeplex.com). They have an OrderedMultiDictionary that is exactly what you are looking for. It allows duplicate keys and it allows you to iterate through all of the duplicate key entries.




回答4:


You are looking for Lookup. Similarly to other dictionary based solutions proposed already, it stores an IEnumerable under each key to handle duplicates.

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



回答5:


You could still use a dictionary. You would just need to change the type of the values to be collections rather than single items:

Dictionary<float, List<T>>

A dictionary be definition does not allow duplicate keys.




回答6:


What you're talking about is a bag. The difference between a bag and a set is that sets are unique whilst bags allow duplicates. {a,b,c} is a set; {a,b,c,a} is a bag.

Grab a copy of the C5 Collections Library. You want the classes HashBag<T> or TreeBag<T>. The difference is that the underlying data store in one is a hash and a red-black tree in the other. Externally, they behave the same. Either should give you what you want.




回答7:


You can do it by overriding CompareTo fucntion. When you add an aelement to a SortedDictionary, it uses CompareTo(), if the result is 0 trows an exception, but you can change the comparator behavior of your key class implementation to return only greather than or lower than (1 or -1)

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



回答8:


What you are looking for is called a heap or priority queue. I'm sure if you google you will find one for C#




回答9:


You should be able to use a SortedDictionary with a custom implementation of IComparer to avoid collisions. For example:

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


来源:https://stackoverflow.com/questions/11801314/equivalent-to-a-sorted-dictionary-that-allows-duplicate-keys

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!