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

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

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

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

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

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

РЕДАКТИРОВАТЬ: Некоторые очень хорошие ответы здесь, а некоторые говорят «больше контекста». Конкретным сценарием был тест dbUnit, где я мог разумно утверждать, что возвращенный набор из запроса содержал только 1 элемент, и я пытался получить доступ к этому элементу.

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

В чем разница между набором и списком .

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

вопрос задан 20.04.2009
Marty Pitt
12990 репутация

18 ответов


  • 167 рейтинг

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

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

    ответ дан Michael Myers, с репутацией 151237, 20.04.2009
  • 72 рейтинг

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

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

    Этот «IndexedSet» НЕ совпадает с SortedSet - в SortedSet элементы сортируются с использованием Comparator (или с использованием их «естественного» порядка).

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

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

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

    ответ дан Sorin Postelnicu, с репутацией 992, 30.05.2010
  • 28 рейтинг

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

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

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

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

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

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

    ответ дан Jonik, с репутацией 49949, 20.04.2009
  • 24 рейтинг

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

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

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

    ответ дан waxwing, с репутацией 15022, 21.04.2009
  • 17 рейтинг

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

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

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

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

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

    ответ дан skiphoppy, с репутацией 35074, 20.04.2009
  • 10 рейтинг

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

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

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

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

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

    ответ дан Andreas Petersson, с репутацией 12899, 28.04.2009
  • 7 рейтинг

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

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

    ответ дан walls, с репутацией 71, 19.01.2010
  • 6 рейтинг

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

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

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

    1. Недостаточно памяти, так как необходимо создать массив для всего набора.
    2. Если набор изменен, представление становится устаревшим.
    ответ дан fortran, с репутацией 49867, 7.01.2011
  • 5 рейтинг

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

    for(A a : set) { 
       visit(a); 
    }
    
    ответ дан Hugo, с репутацией 3308, 20.04.2009
  • 5 рейтинг

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

    ответ дан jsight, с репутацией 21024, 20.04.2009
  • 3 рейтинг

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

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

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

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

    ответ дан buchweizen, с репутацией 31, 18.08.2010
  • 2 рейтинг

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

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

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

    Хотя структура данных Set обычно может быть реализована с помощью HashTable / HashMap или Структура данных BalancedTree , для быстрого обнаружения, существует ли элемент и добавление несуществующего элемента, обычно сложная реализация , установленная в , может достигнуть 180113868 раз за неделю 188913880, что может быть реализовано в случаях. contains операция. В Java HashSet является наиболее распространенной используемой реализацией Set , он реализуется путем вызова API HashMap, а HashMap реализуется с использованием с использованием отдельного сцепления со связанными списками (комбинация Array и 2List).

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

    ответ дан coderz, с репутацией 2319, 1.04.2015
  • 1 рейтинг

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

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

    // Хотелось бы, чтобы в интерфейсе Set был элемент get-random-random.

    ответ дан Dan, с репутацией 50, 21.05.2012
  • 1 рейтинг

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

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

    ответ дан pippi longstocking, с репутацией 680, 10.06.2016
  • 1 рейтинг

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

    ответ дан Janus Troelsen, с репутацией 13061, 2.02.2012
  • 0 рейтинг

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

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

    ответ дан Vitaly Sazanovich, с репутацией 456, 27.01.2014
  • 0 рейтинг

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

    import java.io.*;
    import java.util.*;
    class GFG {
    public static void main (String[] args) {
        HashSet  mySet=new HashSet();
        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.

    ответ дан Prithvi Venu, с репутацией 94, 29.08.2018
  • -1 рейтинг

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

    public T getElement(Set set, T element) {
    T result = null;
    if (set instanceof TreeSet
    ) {
        T floor = ((TreeSet) set).floor(element);
        if (floor != null && floor.equals(element))
        result = floor;
    } else {
        boolean found = false;
        for (Iterator it = set.iterator(); !found && it.hasNext();) {
        if (true) {
            T current = it.next();
            if (current.equals(element)) {
            result = current;
            found = true;
            }
        }
        }
    }
    return result;
    }
    
    ответ дан lala, с репутацией 7, 20.06.2010