Эквивалент сортированного словаря, который позволяет дублировать ключи

Мне нужна структура данных, которая может сортировать объекты с помощью поплавковых ключей, с которыми они связаны. Проблема в том, что ключи представляют собой стоимость, поэтому часто дублируются, меня это не волнует, потому что, если у двух есть такая же стоимость, я просто возьму первый, так как это не имеет никакого значения, проблема в том, что компилятор жалуется.

Существует ли структура данных, которая ведет себя одинаково, но позволяет дублировать ключи?

EDIT - мне все еще нужны дубликаты, потому что, если кто-то оказывается тупиком, я хватаю следующий (это узлы в поиске *)

чтобы просто быть понятным, ему нужно разрешить дублирование ключей, отсортированных по порядку.

Ответ 1

Вы пишете:

эквивалент словаря, который позволяет дублировать ключи

Мне нужна структура данных, которая может сортировать объекты по поплавковым ключам, с которыми они связаны, младший сначала.

Словарь не сохраняет элементы, отсортированные по ключам, поэтому структура, которую вы ищете, на самом деле не эквивалентна Dictionary. То, что вы хотите, похоже на SortedList или SortedDictionary, за исключением того, что оно должно допускать дублирование ключей.

В .NET такого класса нет. Однако у вас есть несколько вариантов:

  • Используйте SortedDictionary<double, List<TValue>>, если вы хотите сохранить все значения, связанные с ключом, даже если вам обычно нужен только первый. При вставке ключа в первый раз создайте новый список и добавьте значение в список. При вставке ключа, который уже существует, выберите список и добавьте его в список.
  • Ваше редактирование означает, что этот подход не применяется к вашей ситуации. Используйте SortedDictionary<double, TValue> и проверяйте дубликаты перед вставкой. Только первое значение для каждой клавиши будет сохранено, поэтому, в отличие от вышеприведенного подхода, вы не можете получить доступ ко второму значению с помощью этого метода.
  • Найдите библиотеку сторонних коллекций, в которой есть класс, который делает то, что вам нужно.

Похожие

Ответ 2

Я часто сталкивался с этой проблемой, и я всегда использую публичную лицензию (то есть бесплатную) Power Collections от Wintellect (http://powercollections.codeplex.com). У них есть OrderedMultiDictionary, который именно вы ищете. Он позволяет дублировать ключи и позволяет выполнять итерацию всех дубликатов ключевых записей.

Ответ 3

Вы ищете Поиск. Подобно другим предлагаемым уже основанным на словах решениям, он хранит IEnumerable под каждым ключом для обработки дубликатов.

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

Ответ 4

Вы можете создать свой собственный класс, который происходит от 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

Ответ 5

Вы все равно можете использовать словарь. Вам просто нужно изменить тип значений для коллекций, а не отдельных элементов:

Dictionary<float, List<T>>

Словарь - это определение не позволяет дублировать ключи.

Ответ 6

То, о чем вы говорите, это сумка. Разница между сумкой и набором заключается в том, что наборы уникальны, а сумки позволяют дублировать. {a, b, c} - множество; {a, b, c, a} - мешок.

Возьмите копию C5 Collections Library. Вам нужны классы HashBag<T> или TreeBag<T>. Разница в том, что основное хранилище данных в одном - это хеш и красно-черное дерево в другом. Внешне они ведут себя одинаково. Либо должен дать вам то, что вы хотите.

Ответ 7

То, что вы ищете, называется heap или priority queue. Я уверен, что если вы Google, вы найдете его для С#

Ответ 8

Вы должны иметь возможность использовать 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);
    }
}

Ответ 9

Вы можете сделать это, переопределив CompareTo fucntion. Когда вы добавляете элемент в SortedDictionary, он использует CompareTo(), если результат равен 0, вызывает исключение, но вы можете изменить поведение компаратора реализации вашего ключевого класса, чтобы вернуться только выше или ниже (1 или -1)

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