Почему не java.утиль.Набор имеет get (int index)?

Я уверен, что есть веская причина, но может кто-нибудь объяснить, почему java.util.Set интерфейс не хватает get(int Index), или любой подобный get() способ?

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

если я знаю, что хочу первый элемент, я могу использовать set.iterator().next(), но в противном случае, кажется, я должен привести к массиву, чтобы получить элемент с определенным индексом?

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

Я уверен, что тот факт, что он исключен из API, означает, что есть веская причина не делать этого-может кто-нибудь просветить меня?

EDIT: Некоторые чрезвычайно отличные ответы здесь, а некоторые говорят "больше контекста". Конкретный сценарий был тестом dbUnit, где я мог разумно утверждать, что возвращаемый набор из запроса имел только 1 элемент, и я пытался получить доступ к этому пункт.

однако вопрос более корректен без сценария, поскольку он остается более сфокусированным:

в чем разница между set и list.

спасибо всем за великолепные ответы ниже.

18 ответов


потому что наборы не имеют порядка. Некоторые реализации (особенно те, которые реализуют java.util.SortedSet interface), но это не является общим свойством наборов.

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


на самом деле это повторяющийся вопрос при написании приложений JavaEE, которые используют объектно-реляционное отображение (например, с Hibernate); и из всех людей, которые ответили здесь, Андреас Петерссон единственный, кто понял реальную проблему и предложил правильный ответ на нее: Java отсутствует UniqueList! (или вы также можете назвать его OrderedSet или IndexedSet).

Maxwing упомянул этот прецедент (в котором вам нужны упорядоченные и уникальные данные), и он предложил SortedSet, но это не то, что нужно Марти Питту.

этот " IndexedSet "не совпадает с SortedSet - в SortedSet элементы сортируются с помощью компаратора (или с использованием их" естественного " упорядочения).

но вместо этого он ближе к LinkedHashSet (который также предложили другие), или даже более того к (Также отсутствующему) "ArrayListSet", потому что он гарантирует, что элементы возвращаются в том же порядке, в котором они были вставлены.

но LinkedHashSet реализация, а не интерфейс! Необходим интерфейс IndexedSet (или ListSet, или OrderedSet, или UniqueList)! Это позволит программисту указать, что ему нужна коллекция элементов, имеющих определенный порядок и без дубликатов, а затем создать ее экземпляр с любой реализацией (например, реализацией, предоставляемой Hibernate).

поскольку JDK является открытым исходным кодом, возможно, этот интерфейс будет наконец включен в Java 7...


просто добавив один пункт, который не был упомянут в mmyers' ответ.

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

каковы соответствующие способы получение данных из набора? (другие чем с помощью итератора)

вы также должны ознакомиться с SortedSet интерфейс (наиболее распространенной реализацией которого является TreeSet).

SortedSet-это набор (т. е. элементы уникальны), который упорядочивается естественный заказ элементов или с помощью некоторых Comparator. Вы можете легко получить доступ к первым и последним элементам, используя first() и last() методы. А SortedSet пригодится время от времени, когда вам нужно сохранить свою коллекцию как без дубликатов, так и в определенном порядке путь.

редактировать: Если вам нужен набор, элементы которого хранятся в порядке вставки (подобно списку), взгляните на LinkedHashSet.


этот вид приводит к вопросу, когда вы должны использовать набор, и когда вы должны использовать список. Обычно совет звучит так:

  1. Если вам нужны упорядоченные данные, используйте List
  2. Если вам нужны уникальные данные, используйте Set
  3. Если вам нужны оба, используйте либо: SortedSet (для данных, упорядоченных компаратором), либо OrderedSet/UniqueList (для данных, упорядоченных вставкой). К сожалению, API Java еще не имеет OrderedSet / UniqueList.

четвертый дело часто заключается в том, что вам не нужны ни. В этом случае вы видите, что некоторые программисты идут со списками, а некоторые с наборами. Лично я считаю очень вредным видеть set как список без заказа - потому что это действительно целый другой зверь. Если вам не нужны такие вещи, как установить уникальность или установить равенство, всегда предпочитайте списки.


Я не уверен, что кто-то написал это именно так, но вам нужно понять следующее:

В наборе нет" первого " элемента.

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

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

люди сталкиваются со всем этим. ЭТОТ. ВРЕМЯ. с системами РСУБД и не понимают. Запрос СУБД возвращает набор записей. Это тот же тип набора из математики: неупорядоченная коллекция элементов, только в этом случае элементы являются записями. Результат запроса RDBMS не имеет гарантированного порядка вообще, если вы не используете предложение ORDER BY, но все время люди предполагают, что это так, а затем отключаются в один прекрасный день, когда форма их данных или кода немного меняется и запускает оптимизатор запросов работать по-другому, и вдруг результаты не выходят в том порядке, в котором они ожидают. Обычно это люди, которые не обращали внимания в классе базы данных (или при чтении документации или учебников), когда им объясняли, что результаты запроса не имеют гарантированного заказа.


некоторые структуры данных отсутствуют в стандартных коллекциях java.

сумка (как набор, но может содержать элементы несколько раз)

UniqueList (упорядоченный список, может содержать каждый элемент только один раз)

кажется, вам понадобится uniquelist в этом случае

Если вам нужны гибкие структуры данных, ВАС МОЖЕТ ЗАИНТЕРЕСОВАТЬ Google Коллекции


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

но почему у нас нет метода get(object), не предоставляя индекс в качестве параметра, а объект, равный тому, который мы ищем? Таким образом, мы можем получить доступ к данным элемента внутри набора, просто зная его атрибуты, используемые методом equal.


Если вы собираетесь сделать много случайных обращений по индексу в наборе, вы можете получить представление массива его элементов:

Object[] arrayView = mySet.toArray();
//do whatever you need with arrayView[i]

однако есть два основных недостатка:

  1. это не эффективная память, так как массив для всего набора должен быть создан.
  2. если набор изменен, представление становится устаревшим.

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


единственная причина, по которой я могу думать об использовании числового индекса в наборе, - это итерация. Для этого используйте

for(A a : set) { 
   visit(a); 
}

Я столкнулся с ситуациями, когда я действительно хотел отсортированныйSet с доступом через индекс (Я согласен с другими плакатами, что доступ к несортированному набору с индексом не имеет смысла). Примером может служить дерево, в котором я хотел, чтобы дети были отсортированы, а дубликаты детей не разрешались.

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

поиск подходящей коллекции в Ява.util или Google collections, я нашел его простым для реализации самостоятельно. Основная идея заключается в том, чтобы обернуть SortedSet и создать список, когда требуется доступ через индекс (и забыть список при изменении SortedSet). Это, конечно, работает эффективно только при изменении обернутого SortedSet и доступ к списку разделяется в течение срока службы коллекции. В противном случае он ведет себя как список, который часто сортируют, т. е. слишком медленно.

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


обратите внимание, что только 2 основные структуры данных могут быть доступны через индекс.

  • массив структура данных может быть доступна через индекс с O(1) сложность времени для достижения get(int index) операции.
  • LinkedList структура данных также может быть доступна через индекс, но с O(n) сложность времени для достижения get(int index) операции.

В Java, ArrayList реализуется с помощью массив сведения структура.

пока Set структура данных обычно может быть реализована через HashTable / HashMap или BalancedTree структура данных для быстрого обнаружения, существует ли элемент и добавить несуществующий элемент, как правило, хорошо реализован Set можно добиться O(1) сложность contains операции. В Java, HashSet является наиболее распространенной используемой реализацией Set, он реализуется путем вызова HashMap API-интерфейс, и HashMap реализуется с помощью отдельная цепочка со связанными списками (комбинация массив и LinkedList).

С Set может быть реализован через другую структуру данных, нет get(int index) способ для этого.


можно сделать new ArrayList<T>(set).get(index)


причина, почему набор интерфейс не имеет вызова типа индекса get или даже чего-то еще более простого, например first() или last(), потому что это неоднозначная операция и, следовательно, потенциально опасная операция. Если метод возвращает набор, и вы вызываете, скажем, метод first() на нем, каков ожидаемый результат, учитывая, что общий набор не дает никаких гарантий на заказ? Результирующий объект может очень хорошо варьироваться между каждым вызовом метода, или он может не и убаюкайте вас ложным чувством безопасности, пока библиотека, которую вы используете, не изменит реализацию внизу, и теперь вы обнаружите, что весь ваш код ломается без особой причины.

предложения по обходным путям, перечисленные здесь, хороши. Если вам нужен индексированный доступ, используйте список. Будьте осторожны с использованием итераторов или toArray с общим набором, потому что а) нет гарантии на заказ и Б) нет гарантии, что заказ не изменится с последующим вызовы или с различными базовыми реализациями. Если вам нужно что-то среднее, SortedSet или LinkedHashSet-это то, что вы хотите.

// Я бы хотел, чтобы интерфейс Set имел элемент get-random-element.


java.util.Set коллекция ООН-заказанные товары. Это не имеет никакого смысла, если набор имеет get (int index), потому что Set не имеет индекса, а также вы можете только угадать значение.

Если вы действительно хотите этого, Закодируйте метод для получения случайного элемента из набора.


Если вы не возражаете против набора для сортировки, вам может быть интересно взглянуть на indexed-tree-map.

расширенные TreeSet/TreeMap предоставляет доступ к элементам по индексу и получение индекса элемента. И реализация основана на обновлении Весов узлов в дереве RB. Поэтому здесь нет итерации или резервного копирования по списку.


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

import java.io.*;
import java.util.*;
class GFG {
public static void main (String[] args) {
    HashSet <Integer> mySet=new HashSet<Integer>();
    mySet.add(100);
    mySet.add(100);
    int n = mySet.size();
    Integer arr[] = new Integer[n];
    arr = mySet.toArray(arr);
    System.out.println(arr[0]);
    }
}

Это будет печатать 100.


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

public T getElement(Set<T> set, T element) {
T result = null;
if (set instanceof TreeSet<?>) {
    T floor = ((TreeSet<T>) set).floor(element);
    if (floor != null && floor.equals(element))
    result = floor;
} else {
    boolean found = false;
    for (Iterator<T> it = set.iterator(); !found && it.hasNext();) {
    if (true) {
        T current = it.next();
        if (current.equals(element)) {
        result = current;
        found = true;
        }
    }
    }
}
return result;
}