Как преобразовать массив в набор в Java


718

Я хотел бы преобразовать массив в набор в Java. Есть несколько очевидных способов сделать это (то есть с помощью цикла), но я хотел бы что-то более аккуратное, что-то вроде:

java.util.Arrays.asList(Object[] a);

Любые идеи?

Ответы:


1228

Нравится:

Set<T> mySet = new HashSet<>(Arrays.asList(someArray));

В Java 9+, если немодифицируемый набор в порядке:

Set<T> mySet = Set.of(someArray);

В Java 10+ параметр общего типа может быть выведен из типа компонента массивов:

var mySet = Set.of(someArray);

10
Я бы пропустил последний <T>, иначе хороший приятель!
деспот

165
@dataoz: неправильно; Arrays.asListявляется O (1).
SLaks

67
Обратите внимание, что если вы используете этот метод в массиве примитивов, таких как int [], он вернет List <int []>, поэтому вы должны использовать классы-обертки, чтобы получить намеченное поведение.
Т. Маркл

6
@AjayGautam: Это только в Гуаве.
SLaks

10
Я буду воспринимать удобочитаемость за эффективность (почти) каждый раз: blog.codinghorror.com/…
Дэвид Карбони

222
Set<T> mySet = new HashSet<T>();
Collections.addAll(mySet, myArray);

Это Collections.addAll (java.util.Collection, T ...) из JDK 6.

Дополнительно: что если наш массив полон примитивов?

Для JDK <8, я бы просто написал очевидный forцикл, чтобы сделать перенос и добавление-набор за один проход.

Для JDK> = 8 привлекательный вариант выглядит примерно так:

Arrays.stream(intArray).boxed().collect(Collectors.toSet());

5
Вы можете сделать это с java.util.Collections.addAll. Кроме того, я бы больше не рекомендовал Commons Collections, поскольку он не генерируется и Guava не существует.
ColinD

14
+1 за то, что он более эффективен, чем ответ SLaks, хотя это не однострочник.
Адриан

1
@ Адриан, я задаю этот вопрос. Я думаю, что addAllбудет O ( N ).
Стив Пауэлл

1
Я считаю, что точка зрения Адриана была о том, как решение SLaks создает экземпляр List, который в конечном итоге отбрасывается. Фактическое влияние этой разницы, вероятно, чрезвычайно минимально, но может зависеть от контекста, в котором вы это делаете - узкие циклы или очень большие наборы могут вести себя очень по-разному между этими двумя вариантами.
JavadocMD

13
Согласно javadoc Collections.addAll () (Java 6): «Поведение этого вспомогательного метода идентично поведению c.addAll (Arrays.asList (elements)), но этот метод, вероятно, будет работать значительно быстрее в большинстве реализаций. "
Берт F

124

С Guava вы можете сделать:

T[] array = ...
Set<T> set = Sets.newHashSet(array);

27
также ImmutableSet.copyOf (массив). (Я хотел бы отметить также, я думаю.)
Кевин Бурриллион

Для фиксированного списка элементов вы можете использовать: ImmutableSet.of (e1, e2, ..., en). Обратите внимание, что вы не сможете изменить этот набор после его создания.
Писарук

1
Будьте осторожны, Javadoc из Гуавы говорит: «Этот метод на самом деле не очень полезен и, скорее всего, в будущем будет устаревшим». Они указывают на стандарт new HashSet<T>(Arrays.asList(someArray)). См. Google.github.io/guava/releases/19.0/api/docs/com/google/common/…
Александр Климетчек,

68

Java 8:

String[] strArray = {"eins", "zwei", "drei", "vier"};

Set<String> strSet = Arrays.stream(strArray).collect(Collectors.toSet());
System.out.println(strSet);
// [eins, vier, zwei, drei]

2
Стоит ли делать это параллельно?
Раффи Хачадурян

@RaffiKhatchadourian Это не обязательно делается параллельно. Arrays.stream не дает никаких обещаний в потоке. Для этого вам нужно будет вызвать параллель () в результирующем потоке.
Феликс С

Вы также можете вызывать parallelStream (). Чтобы ответить на вопрос @ RaffiKhatchadourian, вероятно, нет. Попробуйте измерить, если вы заметили какие-либо проблемы с производительностью.
Рэнди Дев

6
Как правило, избегайте параллельных. По умолчанию он использует один пул потоков в вашем приложении, и затраты на запуск потоков и объединение хуже, чем последовательная потоковая передача через сотни элементов. Только в очень немногих ситуациях параллель действительно приносит пользу.
tkruse


30

Java 8

У нас также есть возможность использования Stream. Мы можем получить поток различными способами:

Set<String> set = Stream.of("A", "B", "C", "D").collect(Collectors.toCollection(HashSet::new));
System.out.println(set);

String[] stringArray = {"A", "B", "C", "D"};
Set<String> strSet1 = Arrays.stream(stringArray).collect(Collectors.toSet());
System.out.println(strSet1);

// if you need HashSet then use below option.
Set<String> strSet2 = Arrays.stream(stringArray).collect(Collectors.toCollection(HashSet::new));
System.out.println(strSet2);

Исходный код Collectors.toSet()показывает, что элементы добавляются один за другим, HashSetно спецификация не гарантирует, что это будет HashSet.

«Нет никаких гарантий относительно типа, изменчивости, сериализуемости или безопасности потоков возвращаемого набора».

Так что лучше использовать более поздний вариант. Выход: [A, B, C, D] [A, B, C, D] [A, B, C, D]

Неизменный набор (Java 9)

Java 9 представил Set.ofстатический метод фабрики, который возвращает неизменный набор для предоставленных элементов или массива.

@SafeVarargs
static <E> Set<E> of​(E... elements)

Проверьте непреложный Набор статических фабричные методы для деталей.

Неизменный набор (Java 10)

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

  1. Set.copyOf(Arrays.asList(array))
  2. Arrays.stream(array).collect(Collectors.toUnmodifiableList());

Метод Collectors.toUnmodifiableList()внутренне использует Set.ofвведенный в Java 9. Также проверьте мой ответ для большего.


1
+1 за Stream.of()- я этого не знал. Небольшое возражение Collectors.toSet(): вы говорите, что спецификация не гарантирует добавление элементов один за другим, но именно это означает: «накапливается ... в новом Set». И это более читабельно - на мой взгляд, предпочтительнее, если вам не нужны гарантии конкретного типа, изменчивости, сериализуемости и безопасности потоков.
Эндрю Спенсер

@AndrewSpencer Spec не гарантирует, что установленная реализация будет HashSet. Это только гарантирует, что это будет, Setи это то, что я имею в виду. Надеюсь, я прояснил это.
akhil_mittal

Извините, и спасибо, я неверно истолковал это как значение "спецификация не гарантирует добавление по одному", а не "спецификация не гарантирует HashSet". Предложил правку для уточнения.
Эндрю Спенсер

19

После того как Arrays.asList(array)вы можете выполнитьSet set = new HashSet(list);

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

public <T> Set<T> GetSetFromArray(T[] array) {
    return new HashSet<T>(Arrays.asList(array));
}

Я надеялся на метод, который возвращает набор непосредственно из массива, существует ли он?

1
Вы можете написать свой собственный, если вы так нетерпеливы :)
Петар Минчев

12

В Eclipse Collections будет работать следующее:

Set<Integer> set1 = Sets.mutable.of(1, 2, 3, 4, 5);
Set<Integer> set2 = Sets.mutable.of(new Integer[]{1, 2, 3, 4, 5});
MutableSet<Integer> mutableSet = Sets.mutable.of(1, 2, 3, 4, 5);
ImmutableSet<Integer> immutableSet = Sets.immutable.of(1, 2, 3, 4, 5);

Set<Integer> unmodifiableSet = Sets.mutable.of(1, 2, 3, 4, 5).asUnmodifiable();
Set<Integer> synchronizedSet = Sets.mutable.of(1, 2, 3, 4, 5).asSynchronized();
ImmutableSet<Integer> immutableSet = Sets.mutable.of(1, 2, 3, 4, 5).toImmutable();

Примечание: я являюсь коммиттером для коллекций Eclipse


7

Быстро: вы можете сделать:

// Fixed-size list
List list = Arrays.asList(array);

// Growable list
list = new LinkedList(Arrays.asList(array));

// Duplicate elements are discarded
Set set = new HashSet(Arrays.asList(array));

и повернуть вспять

// Create an array containing the elements in a list
Object[] objectArray = list.toArray();
MyClass[] array = (MyClass[])list.toArray(new MyClass[list.size()]);

// Create an array containing the elements in a set
objectArray = set.toArray();
array = (MyClass[])set.toArray(new MyClass[set.size()]);

6

Я написал ниже из совета выше - укради это ... это приятно!

/**
 * Handy conversion to set
 */
public class SetUtil {
    /**
     * Convert some items to a set
     * @param items items
     * @param <T> works on any type
     * @return a hash set of the input items
     */
    public static <T> Set<T> asSet(T ... items) {
        return Stream.of(items).collect(Collectors.toSet());
    }
}

Arrays.stream может быть лучше, чем Stream.of для вышеупомянутого.
Эшли Фриз

5

Там было много хороших ответов уже, но большинство из них не будет работать с массивом примитивов (например int[], long[], char[],byte[] и т.д.)

В Java 8 и выше, вы можете связать массив с:

Integer[] boxedArr = Arrays.stream(arr).boxed().toArray(Integer[]::new);

Затем преобразуйте в набор, используя поток:

Stream.of(boxedArr).collect(Collectors.toSet());

0

Иногда помогает использование некоторых стандартных библиотек. Попробуйте взглянуть на коллекции Apache Commons . В этом случае ваши проблемы просто трансформируются в нечто подобное

String[] keys = {"blah", "blahblah"}
Set<String> myEmptySet = new HashSet<String>();
CollectionUtils.addAll(pythonKeywordSet, keys);

А вот и коллекция CollectionsUtils Javadoc


4
пользователь может не использовать Apache Commons
Adrian

если пользователь не использует Apache Commons, то это его первая ошибка.
Джериль Кук

3
почему вы используете это вместо java.util.Collections.addAll(myEmptySet, keys);??
djeikyb

0

Использовать CollectionUtilsили ArrayUtilsизstanford-postagger-3.0.jar

import static edu.stanford.nlp.util.ArrayUtils.asSet;
or 
import static edu.stanford.nlp.util.CollectionUtils.asSet;

  ...
String [] array = {"1", "q"};
Set<String> trackIds = asSet(array);

0

В Java 10 :

String[] strs = {"A", "B"};
Set<String> set = Set.copyOf(Arrays.asList(strs));

Set.copyOfвозвращает неизменяемое, Setсодержащее элементы данного Collection.

 Данное Collectionне должно быть null, и оно не должно содержать каких - либо nullэлементов.


0
private Map<Integer, Set<Integer>> nobreaks = new HashMap();
nobreaks.put(1, new HashSet(Arrays.asList(new int[]{2, 4, 5})));
System.out.println("expected size is 3: " +nobreaks.get(1).size());

выход

expected size is 3: 1

изменить на

nobreaks.put(1, new HashSet(Arrays.asList( 2, 4, 5 )));

выход

expected size is 3: 3

-1

Для тех, кто решает для Android:

Kotlin Collections Solution

Звездочка *является spreadоператором. Он применяет все элементы в коллекции по отдельности, каждый из которых передается в порядке varargпараметра метода. Это эквивалентно:

val myArray = arrayOf("data", "foo")
val mySet = setOf(*myArray)

// Equivalent to
val mySet = setOf("data", "foo")

// Multiple spreads ["data", "foo", "bar", "data", "foo"]
val mySet = setOf(*myArray, "bar", *myArray)

Передача без параметров setOf() приводит к пустому набору.

В дополнение к этому setOfвы также можете использовать любой из них для определенного типа хеша:

hashSetOf()
linkedSetOf()
mutableSetOf()
sortableSetOf()

Вот как явно определить тип элемента коллекции.

setOf<String>()
hashSetOf<MyClass>()

-2

new HashSet<Object>(Arrays.asList(Object[] a));

Но я думаю, что это будет более эффективным:

final Set s = new HashSet<Object>();    
for (Object o : a) { s.add(o); }         

Это не будет более эффективным (по крайней мере, не стоит думать).
ColinD

3
В версии конструктора, например, начальная емкость HashSetзадается на основе размера массива.
ColinD

3
этот ответ не так глуп, как кажется: «Collections.addAll (mySet, myArray);» from java.util.Collections использует тот же итератор, но плюс одну логическую операцию. Плюс, как указал Берт Ф. Collections.addAll «вероятно, будет работать значительно быстрее в большинстве реализаций», чем c.addAll (Arrays.asList (elements))
Зорб

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.