Подтвердить что ты не робот

Как получить первый элемент из java.util.Set?

У меня есть экземпляр Set:

Set<String> siteIdSet = (Set<String>) pContext.getParent().getPropertyValue(getCatalogProperties().getSitesPropertyName());

pContext.getParent().getPropertyValue() - это готовый код, на который у меня нет никакого элемента управления для изменения.

Требование:

Я хотел получить из него первый элемент по умолчанию (всегда). Тем не менее, я не смог найти метод get(index), как в ArrayList.

Следовательно, прямо сейчас я делаю так.

for (Iterator<String> it = siteIdSet.iterator(); it.hasNext();) {
    siteId = it.next();
    break;
}

Есть ли какой-либо (другой) эффективный способ (короткий и лучший) для достижения этого?

4b9b3361

Ответ 1

В документах Oracle:

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

В Установить теорию, "набор" представляет собой набор отдельных объектов, которые рассматриваются как самостоятельный объект. "- [Википедия - Установить].

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

Не может быть никакого смысла получать "первый" элемент из набора, но если вам нужно только один объект из набора (без каких-либо гарантий относительно того, какой объект), вы можете сделать следующее:

for(String aSiteId: siteIdSet) {
    siteId = aSiteId;
    break;
}

Это немного более короткий путь (чем метод, который вы опубликовали), чтобы получить "первый" объект Set, однако, поскольку Итератор все еще создается (под капотом), он не дает каких-либо преимуществ в производительности.

Ответ 2

Это вернет первый элемент

set.iterator().next();

Ответ 3

Или, используя Java8:

Object firstElement = set.stream().findFirst().get();

И тогда вы можете делать вещи с этим сразу:

set.stream().findFirst().ifPresent(<doStuffHere>);

Или, если вы хотите предоставить альтернативу в случае, если элемент отсутствует (мой пример возвращает новую строку по умолчанию):

set.stream().findFirst().orElse("Empty string");

Вы даже можете выдать исключение, если отсутствует первый элемент:

set.stream().findFirst().orElseThrow(() -> new MyElementMissingException("Ah, blip, nothing here!"));

Престижность Alex Vulaj за то, что он побудил меня предоставить больше примеров помимо первоначального захвата первого элемента.

Ответ 4

Set - это уникальный набор элементов. Поэтому нет понятия первого элемента. Если вы хотите, чтобы элементы отсортированы по порядку, вы можете использовать TreeSet, из которого вы можете получить первый элемент, используя TreeSet # первый().

Ответ 5

TL;DR

Вызвать TreeSet::first

Переместите элементы и вызовите first().

new TreeSet<String>( 
    pContext.getParent().getPropertyValue( … )   // Transfer elements from your `Set` to this new `TreeSet`, an implementation of the `SortedSet` interface. 
).first()

Set Не имеет порядка

Как говорили другие, Set по определению не имеет порядка. Поэтому запрос "первого" элемента не имеет значения.

Некоторые реализации Set имеют порядок, такой как порядок добавления элементов. Этот неофициальный порядок может быть доступен через Iterator. Но этот порядок случайен и не гарантирован. Если вам повезет, реализация, поддерживающая ваш Set, действительно может быть SortedSet.

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

Object firstElement = mySet.iterator().next();

Чтобы напрямую обратиться к Вопросу... Нет, не самый короткий способ получить первый элемент из итератора при обработке возможного случая пустого набора. Тем не менее, я предпочел бы тест if для isEmpty, а не цикл for.

if ( ! mySet.isEmpty() ) {
    Object firstElement = mySet.iterator().next();
)

Использовать SortedSet

Если вам нужно поддерживать порядок сортировки в Set, используйте SortedSet. Такие реализации включают в себя:

Использовать LinkedHashSet Для ввода-заказа

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

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

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

Ответ 6

Set не обеспечивает упорядочение. Нет никакой гарантии, что вы всегда получите "первый" элемент, даже если вы используете итератор над HashSet, как вы это делали в вопросе.

Если вам нужно иметь предсказуемое упорядочение, вам нужно использовать LinkedHashSet. Когда вы перебираете LinkedHashSet, вы получите элементы в том порядке, в который вы вставили. Вам все равно нужно использовать итератор, потому что для метода get в LinkedHashSet вам понадобится использовать конкретный класс везде.

Ответ 7

Как вы упомянули pContext.getParent().getPropertyValue return Set. Вы можете преобразовать Set в List, чтобы получить первый элемент. Просто измените свой код:

 Set<String> siteIdSet = (Set<String>) pContext.getParent().getPropertyValue(..);
 List<String> siteIdList=new ArrayList<>(siteIdSet);

 String firstItem=siteIdList.get(0);

Ответ 8

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

Ответ 9

Это сложный вопрос, который я встал против самого себя. java.util.LinkedHashSet поддерживает связанный список его содержимого (добавочно-упорядоченный по умолчанию), но не предоставляет никаких аксессуаров. Другие типы структуры не смогут обеспечить O (1) на add(), remove() и contains().

Вы можете использовать LinkedHashSet и получить его iterator(), захватить один элемент и отбросить его. Если вы не слишком заботитесь о скорости или памяти, когда часто это делаете для множества разных наборов, это, вероятно, ваше решение... но это казалось мне расточительным. Кроме того, у меня была небольшая дополнительная желаемая функциональность.

В конце концов я написал свой собственный класс, получивший название RandomAccessLinkedHashSet, который одновременно поддерживает хеш-таблицу, двусвязный список и не имеющий отношения к порядку массив. Я написал это, чтобы соответствовать как Set, так и Deque, хотя реализация Deque немного отрывочна, так как она не сможет push() элементов, которые она уже содержит, немного растягивается для контракта интерфейса. Поддержание третьей структуры, массив, вовсе не требуется для того, что вы делаете, но также позволяет получить доступ к случайному элементу в наборе любой возможной емкости, которая может фактически обеспечить случайное значение.

Если вам интересно, я могу предоставить этот источник. Я еще не Serialized, но он отлично работает во время выполнения.

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

Ответ 10

Это работает:

Object firstElement = set.toArray()[0]; 

Ответ 11

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

Ответ 12

Установить по определению не упорядочен.

Вероятно, вы используете неправильную коллекцию.

Ответ 13

Вектор имеет несколько удобных функций:

Vector<String> siteIdVector = new Vector<>(siteIdSet);
String first = siteIdVector.firstElement();
String last = siteIdVector.lastElement();

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