Cách chuyển đổi một mảng thành một tập hợp trong Java


717

Tôi muốn chuyển đổi một mảng thành Set trong Java. Có một số cách rõ ràng để làm điều này (tức là với một vòng lặp) nhưng tôi muốn một cái gì đó gọn gàng hơn, đại loại như:

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

Có ý kiến ​​gì không?

Câu trả lời:


1227

Như thế này:

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

Trong Java 9+, nếu bộ không thể thay đổi là ok:

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

Trong Java 10+, tham số kiểu chung có thể được suy ra từ kiểu thành phần mảng:

var mySet = Set.of(someArray);

10
Tôi sẽ bỏ qua <T> cuối cùng, nếu không thì oneliner tốt đẹp!
despot

165
@dataoz: Sai; Arrays.asListlà O (1).
SLaks

67
Lưu ý rằng nếu bạn sử dụng phương thức này trên một mảng các nguyên hàm như int [], nó sẽ trả về một Danh sách <int []> vì vậy bạn nên sử dụng các lớp bao bọc để có được hành vi dự định.
T. Markle

6
@AjayGautam: Điều đó chỉ có ở ổi.
SLaks

10
Tôi sẽ có được khả năng đọc về hiệu quả (gần như) mỗi lần: blog.codingh khiếp.com / từ
David Carboni

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

Đó là Bộ sưu tập.add ALL (java.util.Collection, T ...) từ JDK 6.

Ngoài ra: nếu mảng của chúng ta đầy nguyên thủy thì sao?

Đối với JDK <8, tôi sẽ chỉ viết forvòng lặp rõ ràng để thực hiện gói và bổ trợ trong một lượt.

Đối với JDK> = 8, một tùy chọn hấp dẫn giống như:

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

5
Bạn có thể làm điều đó với java.util.Collections.addAll. Thêm vào đó, tôi sẽ không đề xuất Bộ sưu tập Commons nữa, những gì với nó không được tạo ra và ổi hiện có.
ColinD

14
+1 vì hiệu quả hơn câu trả lời của SLaks, mặc dù đó không phải là một lớp lót.
Adrian

1
@Adrian Tôi thắc mắc điều đó. Tôi nghĩ addAllsẽ là O ( n ).
Steve Powell

1
Tôi tin rằng quan điểm của Adrian là về cách giải pháp của SLaks tạo ra một thể hiện Danh sách cuối cùng bị loại bỏ. Tác động thực sự của sự khác biệt đó có lẽ là cực kỳ nhỏ, nhưng có thể phụ thuộc vào bối cảnh bạn đang thực hiện điều này - các vòng lặp chặt chẽ hoặc các bộ rất lớn có thể hành xử rất khác nhau giữa hai tùy chọn này.
JavadocMD

13
Theo Collections.addAll () javadoc (Java 6): "Hành vi của phương thức tiện lợi này giống hệt với c.addAll (Arrays.asList (yếu tố)), nhưng phương thức này có thể chạy nhanh hơn đáng kể trong hầu hết các triển khai. "
Bert F

124

Với ổi bạn có thể làm:

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

27
cũng bất biến Set.copyOf (mảng). (Tôi cũng muốn chỉ ra, tôi đoán vậy.)
Kevin Bourrillion

Đối với một danh sách cố định các yếu tố bạn có thể sử dụng: ImmutableSet.of (e1, e2, ..., en). Lưu ý rằng bạn sẽ không thể thay đổi Bộ này sau khi tạo.
pisaruk

1
Được cảnh báo, Guava javadoc nói: "Phương pháp này thực sự không hữu ích lắm và có khả năng sẽ bị từ chối trong tương lai." Họ hướng tới tiêu chuẩn new HashSet<T>(Arrays.asList(someArray)). Xem google.github.io/guava/release/19.0/api/docs/com/google/common/ Kẻ
Alexander Klimetschek

67

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
Có đáng để làm điều này song song?
Raffi Khatchadourian

@RaffiKhatchadourian Điều này không nhất thiết phải được thực hiện song song. Arrays.stream không thực hiện bất kỳ lời hứa nào trên luồng. Bạn sẽ phải gọi song song () trên luồng kết quả cho điều đó.
Felix S

Bạn cũng có thể gọiallelStream (). Để trả lời câu hỏi của @ RaffiKhatchadourian, có lẽ là không. Hãy thử đo nếu bạn nhận thấy bất kỳ vấn đề hiệu suất.
Randy the Dev

6
Nói chung, tránh song song. Theo mặc định, nó sử dụng một luồng xử lý duy nhất trên ứng dụng của bạn và chi phí để bắt đầu các chuỗi và tham gia còn tệ hơn so với việc truyền tuần tự qua hàng trăm mục. Chỉ trong rất ít tình huống song song thực sự mang lại lợi ích.
tkruse

45

Varargs cũng sẽ hoạt động!

Stream.of(T... values).collect(Collectors.toSet());

2
cách tốt hơn mà 2-3 lót.
giác quan

30

Java 8

Chúng tôi có tùy chọn sử dụng Streamlà tốt. Chúng tôi có thể nhận luồng theo nhiều cách khác nhau:

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

Mã nguồn của Collectors.toSet()chương trình cho thấy các phần tử được thêm lần lượt vào một HashSetnhưng một đặc điểm kỹ thuật không đảm bảo nó sẽ là a HashSet.

"Không có sự đảm bảo nào về loại, tính biến đổi, tính tuần tự hoặc độ an toàn của luồng được đặt lại."

Vì vậy, tốt hơn là sử dụng các tùy chọn sau. Đầu ra là: [A, B, C, D] [A, B, C, D] [A, B, C, D]

Bộ bất biến (Java 9)

Java 9 đã giới thiệu Set.ofphương thức nhà máy tĩnh trả về tập hợp bất biến cho các phần tử được cung cấp hoặc mảng.

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

Kiểm tra các phương pháp nhà máy tĩnh bất biến để biết chi tiết.

Bộ bất biến (Java 10)

Chúng ta cũng có thể có được một bộ bất biến theo hai cách:

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

Phương thức Collectors.toUnmodifiableList()bên trong sử dụng Set.ofgiới thiệu trong Java 9. Ngoài ra, hãy kiểm tra câu trả lời này của tôi để biết thêm.


1
+1 cho Stream.of()- Tôi không biết cái đó. Một vấn đề nhỏ về Collectors.toSet(): bạn nói rằng thông số kỹ thuật không đảm bảo thêm từng yếu tố một, nhưng đó là ý nghĩa của nó: "tích lũy ... thành một cái mới Set". Và nó dễ đọc hơn - rất phù hợp với suy nghĩ của tôi, nếu bạn không cần sự đảm bảo về loại cụ thể, tính dễ biến đổi, tính tuần tự và an toàn luồng.
Andrew Spencer

@AndrewSpencer Spec không đảm bảo rằng việc thực hiện cài đặt sẽ được HashSet. Nó chỉ đảm bảo rằng nó sẽ là một Setvà đó là những gì tôi muốn nói. Hy vọng tôi làm rõ nó.
akhil_mittal

Xin lỗi, và cảm ơn, tôi đã đọc sai nó thành "spec không đảm bảo được thêm từng cái một" thay vì "spec không đảm bảo Hashset". Đề xuất một chỉnh sửa để làm rõ.
Andrew Spencer

19

Sau khi bạn làm Arrays.asList(array)bạn có thể thực hiệnSet set = new HashSet(list);

Đây là một phương pháp mẫu, bạn có thể viết:

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

Tôi đã hy vọng cho một phương thức trả về một tập hợp trực tiếp từ một mảng, liệu nó có tồn tại không?

1
Bạn có thể tự viết, nếu bạn rất háo hức :)
Petar Minchev

12

Trong Bộ sưu tập Eclipse , những điều sau đây sẽ hoạt động:

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();

Lưu ý: Tôi là người đi làm cho Bộ sưu tập Eclipse


7

Nhanh chóng: bạn có thể làm:

// 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));

và để đảo ngược

// 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

Tôi đã viết những điều dưới đây từ những lời khuyên ở trên - ăn cắp nó ... thật tuyệt!

/**
 * 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 có thể tốt hơn Stream.of cho phần trên.
Ashley Frieze

5

Hiện đã có rất nhiều câu trả lời tuyệt vời đã có, nhưng hầu hết trong số họ sẽ không làm việc với mảng nguyên thủy (như int[], long[], char[], byte[], vv)

Trong Java 8 trở lên, bạn có thể đóng hộp mảng với:

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

Sau đó chuyển đổi thành thiết lập bằng cách sử dụng luồng:

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

0

Đôi khi sử dụng một số thư viện tiêu chuẩn giúp rất nhiều. Hãy thử nhìn vào Bộ sưu tập Apache Commons . Trong trường hợp này, các vấn đề của bạn chỉ đơn giản là chuyển thành một cái gì đó như thế này

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

Và đây là bộ sưu tập javadoc


4
người dùng không được sử dụng chung apache
Adrian

Nếu người dùng không sử dụng apache commons, thì đó là lỗi đầu tiên của anh ta.
Jeryl Cook

3
Tại sao bạn lại sử dụng cái này thay vì java.util.Collections.addAll(myEmptySet, keys);??
djeikyb

0

Sử dụng CollectionUtilshoặc ArrayUtilstừ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

Trong Java 10 :

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

Set.copyOftrả về một giá trị không thể thay đổi Setcó chứa các phần tử đã cho Collection.

 Cái đã cho Collectionkhông được null, và nó không được chứa bất kỳ nullyếu tố nào .


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());

đầu ra là

expected size is 3: 1

thay đổi nó thành

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

đầu ra là

expected size is 3: 3

-1

Đối với bất cứ ai giải quyết cho Android:

Giải pháp bộ sưu tập của Kotlin

Dấu hoa thị *spreadtoán tử. Nó áp dụng tất cả các phần tử trong một bộ sưu tập riêng lẻ, từng phần được truyền vào một varargtham số phương thức. Nó tương đương với:

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)

Vượt qua không có tham số setOf()dẫn đến một tập hợp trống.

Ngoài ra setOf, bạn cũng có thể sử dụng bất kỳ trong số này cho một loại băm cụ thể:

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

Đây là cách xác định loại mục bộ sưu tập một cách rõ ràng.

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

-2

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

Nhưng tôi nghĩ rằng điều này sẽ hiệu quả hơn:

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

Điều đó sẽ không thực sự hiệu quả hơn (ít nhất là không đáng suy nghĩ).
ColinD

3
Với phiên bản constructor, chẳng hạn, dung lượng ban đầu của HashSetđược đặt dựa trên kích thước của mảng.
ColinD

3
câu trả lời này không quá ngớ ngẩn vì có vẻ như: 'Collections.add ALL (my Set, myArray);' từ java.util.Collections sử dụng cùng một trình vòng lặp nhưng cộng với một thao tác boolean. Thêm vào đó, như Bert F đã chỉ ra Bộ sưu tập.add ALL "có khả năng chạy nhanh hơn đáng kể trong hầu hết các triển khai" so với c.addAll (Arrays.asList (yếu tố))
Zorb

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.