Индекс повторяющегося элемента в connectedHashSet

Я добавляю некоторые значения в LinkedHashSet и на основе add() вывод метода т.е. истина / ложь, я выполняю другие операции.

Если Set содержит дубликат элемента, он возвращает ложь, и в этом случае я хочу знать индекс дубликата элемента в Set так как мне нужно использовать этот индекс где-то еще. Будучи "связанной" коллекцией, должен быть какой-то способ получить индекс, но я не смог найти ничего подобного в Set/LinkedHashSet API.

1 ответ

Решение

LinkedHashSet само по себе явно не индексируется. Если вам требуется индекс, используя Set для такого применения обычно это признак неправильной абстракции и / или паршивого программирования. LinkedHashSet только гарантирует вам предсказуемый порядок итераций, а не правильную индексацию элементов. Вы должны использовать List в таких случаях, поскольку этот интерфейс дает вам гарантию индексации. Однако вы можете вывести индекс, используя несколько методов, например (не рекомендуется, обратите внимание):

а) использовать индексированную итерацию в коллекции (например, с for цикл), поиск дубликатов и разрыв, когда он найден; это O(N) сложность для получения индекса,

Object o; // this is the object you want to add to collection
if ( !linkedHashSet.add(o) ) {
    int index = 0;
    for( Object obj : linkedHashSet ) {
        if ( obj == o ) // or obj.equals(o), depending on your code's semantics
            return index;
        index++;
    }
}

б) использовать .toArray() и найти элемент в массиве, например,

Object o; // this is the object you want to add to collection
int index;
if ( !linkedHashSet.add(o) )
    index = Arrays.asList(linkedHashSet.toArray()).indexOf(o);

опять же, O(n) сложность получения индекса.

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

Мне нужно использовать этот индекс где-то еще

... если это действительно так, используя Set 99% времени неправильно само по себе.

Вы можете, с другой стороны, использовать Map (HashMap например), содержащий [index,Object] (или же [Object,index] в зависимости от точного варианта использования) пар в нем. Это потребовало бы немного рефакторинга, но это IMO предпочтительный способ сделать это. Это даст вам тот же порядок сложности для большинства операций, что и LinkedHashSet, но вы получите O(1) для получения индекса по существу бесплатно (Java HashSet использования HashMap внутренне в любом случае, так что вы не теряете память, заменяя HashSet с HashMap).

Еще лучшим способом было бы использовать класс, явно обрабатывающий целочисленные карты - смотрите HashMap и int в качестве ключа для получения дополнительной информации; tl; dr - http://trove.starlight-systems.com/ имеет TIntObjectHashMap & TObjectIntHashMap, давая вам, возможно, лучшую скорость для таких операций возможно.

Другие вопросы по тегам