Почему у java.util.Set нет (int index)?

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

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

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

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

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

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

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

Какая разница между установкой и списком.

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

Ответы

Ответ 1

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

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

Ответ 2

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

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

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

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

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

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

Ответ 3

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

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

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

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

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

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

Ответ 4

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

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

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

Ответ 5

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

В наборе нет элемента "first".

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

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

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

Ответ 6

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

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

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

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

если вам нужны гибкие структуры данных, вас может заинтересовать Коллекции Google

Ответ 7

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

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

Ответ 8

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

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

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

  • Это не эффективная память, так как необходимо создать массив для всего набора.
  • Если набор изменен, представление становится устаревшим.

Ответ 9

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

Ответ 10

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

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

Ответ 11

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

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

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

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

Ответ 12

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

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

В Java ArrayList реализуется с использованием структуры Array.

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

Так как Установить можно реализовать с помощью другой структуры данных, для него нет метода get(int index).

Ответ 13

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

Ответ 14

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

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

// Однако я хочу, чтобы интерфейс Set имел случайный элемент get-random.

Ответ 15

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

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

Ответ 16

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

Улучшенный TreeSet/TreeMap обеспечивает доступ к элементам по индексу или получение индекса элемента. И реализация основана на обновлении весов node в дереве RB. Итак, нет итераций или резервных копий здесь.

Ответ 17

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

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.

Ответ 18

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

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;
}