Найти или вставить только с одним поиском в словаре c # - PullRequest
10 голосов
/ 20 июня 2011

Я бывший программист на C ++ / STL, пытаюсь написать алгоритм быстрого марширования с использованием технологии c # /. NET ...

Я ищу эквивалент STL-метода "map :: insert"который вставляет значение в данный ключ, если он не существует, иначе возвращает итератор для существующей пары ключ-значение.

Единственный способ, который я нашел, это сделать с двумя поисками: один внутри TryGetValue и другой в методе Add:

List<Point> list;
if (!_dictionary.TryGetValue (pcost, out list))
{
    list = new List<Point> ();
    dictionary.Add (pcost, list);
}
list.Add (new Point { X = n.x, Y = n.y });

Есть ли что-то, что объясняет, почему это невозможно при использовании контейнеров .NET?Или я что-то упустил?

Спасибо.

Ответы [ 5 ]

11 голосов
/ 20 июня 2011

Вы можете просто присвоить свое значение следующим образом:

var dict = new Dictionary<int, int>();
dict[2] = 11;

если значение с ключом 2 не существует - оно будет добавлено, а в противном случае оно будет просто переопределено.

Словарь не имеет метода GetOrAdd, но ConcurrentDictionary из C # 4.0 имеет:

var dict = new ConcurrentDictionary<int, int>();
dict[2] = 10;
int a = dict.GetOrAdd(2, 11);// a == 10
2 голосов
/ 05 мая 2013

К сожалению, в реализации bcl такого нет. Ближайшая альтернатива - два поиска, но у одного может быть общий метод расширения, чтобы упростить его, как показано здесь

public static T GetOrAdd<S, T>(this IDictionary<S, T> dict, S key, 
                               Func<T> valueCreator)
{
    T value;
    return dict.TryGetValue(key, out value) ? value : dict[key] = valueCreator();
}

Но есть реализация C5 , которая делает это «из коробки». Определение метода выглядит следующим образом:

public virtual bool FindOrAdd(K key, ref V value)
{

}

Я не знаю, почему они не принимают Func<V> вместо V для отсрочки создания объекта. С5 имеет много хороших подобных трюков, например,

public virtual bool Remove(K key, out V value)

public virtual bool Update(K key, V value, out V oldvalue)

public virtual bool UpdateOrAdd(K key, V value, out V oldvalue)
2 голосов
/ 20 июня 2011

Есть ли что-то, что объясняет, почему это невозможно с помощью .NET контейнеры?

Не зная реального фона, я предполагаю, что это из-за простоты словаря. Существуют только основные, простые для понимания функции: Add, Remove a.s.o., в то время как оператор индекса немного творит волшебство, которое, вероятно, предполагалось интуитивно понятным.

2 голосов
/ 20 июня 2011

Стандартный словарь общего назначения не поддерживает это, требуется 2 поиска. Хотя стоимость поиска обычно незначительна, так что это не проблема, и вы часто можете получить лучшие результаты, настраивая другие части системы, вместо того, чтобы пытаться микрооптимизировать поиск по словарю.

Единственный словарь, который поставляется с .net, который поддерживает это, о котором я знаю, это ConcurrentDictionary с методом GetOrAdd . Хотя теперь вы платите за синхронизацию.

0 голосов
/ 20 июня 2011

Вы можете создать метод расширения для этого:

IDictionary<string, Point> _dictionary = GetDictionary();
_dictionary.GetOrAdd( "asdf" ).Add( new Point(14, 15) );

// ... elsewhere ...
public static class DictionaryExtensions {
    public static List<TValue> GetOrAdd<TKey, TValue>( this IDictionary<TKey, List<TValue>> self, TKey key ) {
        List<TValue> result;
        self.TryGetValue( key, out result );
        if ( null == result ) {
            // the key value can be set to the null
            result = new List<TValue>();
            self[key] = result;
        }

        return result;
    }
}
...