Шаблон или антипаттерн: использование свойства value в качестве ключа в словаре / Hashmap - PullRequest
0 голосов
/ 23 марта 2012

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

В Java это выглядит так:

private HashMap<String, VariableCondition> m_conditions = new HashMap<String, VariableCondition>();

// ...
m_conditions.put(var, new VariableCondition(var, value));

Было бы критично, если бы HashMap был доступен снаружи объекта. Но даже в качестве переменной-члена вы должны заботиться о согласованности HashMap сами.

Есть ли альтернативный шаблон для реализации варианта использования. Использование списка было бы возможно, но вы должны перебирать весь список для каждого доступа.

Ответы [ 4 ]

1 голос
/ 29 июня 2012

Если ваша переменная может иметь только одно значение условия, это прекрасно, но IMO проще иметь карту, потому что пара {переменная, значение} сама является парой {ключ, значение}, поэтому вам не нужна абстракция VariableCondition.

1 голос
/ 23 марта 2012

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

Если вы используете java, вы можете рассмотреть метод uniqueIndex класса Maps в guava.

1 голос
/ 23 марта 2012

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

сбор вещей:

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

List<Event> events = dearDataStorePlzGiveMeDates(); 
TreeMap<Date, List<Event>> byDay = new TreeMap<>(); 
for( Event e : events ){
    List<Event> forDay = byDay.get( e.getDate() ); 
    if( forDay == null ) byDay.put( forDay = new List<Event>() ); 

    forDay.add( e ); 
}

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

обратите внимание, что это было бы сделано совсем по-другому в функциональных языках (отображать события на даты, сортировать, затем собирать события для каждой из этих дат; очень медленно, но с 1 строкой).

как грязная замена комплектов

Еще одна вещь, если часто требуется, - это сделать некоторую структуру данных уникальной по сумасшедшему критерию, сохраняя при этом один экземпляр связанных данных. Учтите это:

List<Creatures> = ...; // from somewhere
HashTable<Integer, Creature> examples = new HashTable<>(); 

for( Create c : creatures ){
    examples.put( c.getNumberLegs(), c ); 
}

теперь вы получаете животное с одной ногой, животное с двумя ногами и т. Д.

1019 * Overal * Я вообще не против этих конструкций, если вы добавите небольшой комментарий о вашем намерении, им должно быть очень легко следовать. Я считаю их особенно полезными, если вам приходится работать с существующими данными, т. Е. У вас нет доступа к хранилищу данных (например, mysql) или хранилище данных просто очень скучно и не знает, как выполнять такие задачи. большое преимущество хеш-карт в их сложности, они имеют O (1) время доступа (O (log n) для древовидных карт), что довольно хорошо. альтернативы

звучит так, как будто вам действительно нужен «указатель», способ быстрого доступа к экземплярам на основе одного из их свойств. в Java есть класс TreeSet для этого. Он имеет сложность O (log n) для всех операций и используется примерно так:

TreeSet<MyClass> indexed = new TreeSet<>( new Comparator<MyClass>(){
    public int compare( MyClass a, MyClass b ){
        // "sort" by the property (assuming they are Integers)
        return a.getThing().compareTo( b.getThing() ); 
    }
}); 

indexed.addAll( theList ); 

внимание, хотя: (1) поведение здесь отличается от вашего примера !! Предположим, что ключи появляются несколько раз, в вашем коде (с хеш-таблицей) последний дубликат выживет. в этом случае первый элемент выжил бы (древовидная карта в основном говорит: «это уже есть, так что ... что угодно») (2) сложность среды выполнения хороша, но намного хуже, чем среда исполнения O (1) при использовании HashMaps.

надеюсь, что это отвечает на ваш вопрос ...

1 голос
/ 23 марта 2012

В .NET есть KeyedCollection , которая делает именно то, что вам нужно.

Но, вообще говоря, связь между ключом и значением является внутренним знанием, которое должно быть скрыто от потребителя.Поэтому я бы рекомендовал инкапсулировать этот хеш в другой класс, который предоставит API для установки / получения данных из него.Ниже приведен быстрый пример на C #:

public class KeyedStorage<K, T>
{
    private readonly Func<T, K> keyFunc;
    private readonly Dictionary<K, T> dictionary = new Dictionary<K, T>();

    public KeyedStorage(Func<T, K> keyFunc)
    {
        this.keyFunc = keyFunc;
    }

    public void Add(T item)
    {
        var key = keyFunc(item);
        dictionary.Add(key, item);
    }

    public T this[K key]
    {
        get { return dictionary[key]; }
    }
}

public class KeyedStorageTests
{
    [Fact]
    public void should_return_item_after_add()
    {
        // arrange
        var keyedStorage = new KeyedStorage<int, string>(s => s.GetHashCode());

        // act
        keyedStorage.Add("werew");

        // assert
        keyedStorage["werew".GetHashCode()]
            .Should()
            .Be("werew");
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...