วิธีการแปลง Array เป็น Set ใน Java


717

ฉันต้องการแปลงอาเรย์เป็น Set ใน Java มีวิธีที่ชัดเจนในการทำเช่นนี้ (เช่นมีวง) แต่ฉันต้องการบางสิ่งบางอย่าง neater เล็กน้อยบางอย่างเช่น:

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

ความคิดใด ๆ

คำตอบ:


1226

แบบนี้:

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> สุดท้ายออกไปเป็นอย่างอื่น oneliner ที่ดี!
despot

165
@dataoz: ผิด; Arrays.asListคือ O (1)
slaks

67
โปรดทราบว่าถ้าคุณใช้วิธีนี้กับอาร์เรย์ของ primitives เช่น int [] มันจะส่งคืน List <int []> ดังนั้นคุณควรใช้คลาส wrapper เพื่อรับพฤติกรรมที่ต้องการ
ต. Markle

6
@AjayGautam: นั่นเป็นเพียงใน Guava
SLaks

10
ฉันจะอ่านง่ายกว่าประสิทธิภาพ (เกือบ) ทุกครั้ง: blog.codinghorror.com/ ..
David Carboni

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

นั่นคือCollections.addAll (java.util.Collection, T ... )จาก JDK 6

นอกจากนี้: จะเป็นอย่างไรถ้าอาร์เรย์ของเราเต็มไปด้วยสิ่งดั้งเดิม

สำหรับ JDK <8 ฉันจะเขียนforลูปที่ชัดเจนเพื่อทำการแรปและ Add-to-set ในครั้งเดียว

สำหรับ JDK> = 8 ตัวเลือกที่น่าดึงดูดคือ:

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

5
java.util.Collections.addAllคุณสามารถทำเช่นนั้นด้วย นอกจากนี้ฉันจะไม่แนะนำคอมมอนส์คอลเล็กชั่นอีกต่อไปสิ่งที่มันไม่ได้รับการสร้างและ Guava ที่มีอยู่
ColinD

14
+1 สำหรับการมีประสิทธิภาพมากกว่าคำตอบของ SLaks แม้ว่าจะไม่ใช่สายการบินเดียว
เอเดรียน

1
@ เอเดรียฉันถามว่า ฉันคิดว่าaddAllจะเป็น O ( n )
Steve Powell

1
ฉันเชื่อว่าจุดสำคัญของเอเดรียนคือวิธีแก้ปัญหาของ SLaks ที่สร้างอินสแตนซ์ของรายการซึ่งถูกโยนทิ้งไปในที่สุด ผลกระทบที่แท้จริงของความแตกต่างนั้นอาจน้อยมาก แต่อาจขึ้นอยู่กับบริบทที่คุณทำเช่นนี้ - ลูปแบบคับหรือชุดที่มีขนาดใหญ่มากอาจทำงานแตกต่างกันมากระหว่างตัวเลือกทั้งสองนี้
JavadocMD

13
ตาม Collections.addAll () javadoc (Java 6): "พฤติกรรมของวิธีการอำนวยความสะดวกนี้เหมือนกับของ c.addAll (Arrays.asList (องค์ประกอบ)) แต่วิธีนี้มีแนวโน้มที่จะทำงานได้เร็วกว่ามากในการใช้งานส่วนใหญ่ "
Bert F

124

ด้วยGuavaคุณสามารถทำได้:

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

27
ยัง ImmutableSet.copyOf (อาร์เรย์) ด้วย (ฉันชอบที่จะชี้ให้เห็นว่ายังเป็นฉันเดา.)
เควิน Bourrillion

สำหรับรายการองค์ประกอบที่แน่นอนคุณสามารถใช้: ImmutableSet.of (e1, e2, ... , en) โปรดสังเกตว่าคุณจะไม่สามารถเปลี่ยนชุดนี้หลังจากการสร้าง
pisaruk

1
ได้รับการเตือน Guava javadoc กล่าวว่า: "วิธีนี้ไม่ได้มีประโยชน์มากจริง ๆ และน่าจะเลิกใช้ในอนาคต" new HashSet<T>(Arrays.asList(someArray))พวกเขาชี้ไปทางมาตรฐาน ดูgoogle.github.io/guava/releases/19.0/api/docs/com/google/common/...
อเล็กซานเด 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
มันคุ้มกับการทำแบบนี้เหรอ?
Raffi Khatchadourian

@RaffiKhatchadourian นี่ไม่จำเป็นต้องทำแบบขนาน Arrays.stream ไม่ได้ให้คำสัญญาใด ๆ กับสตรีม คุณจะต้องเรียกขนาน () บนสตรีมที่ได้
เฟลิกซ์ S

คุณสามารถโทร parallelStream () เพื่อตอบคำถามของ @ RaffiKhatchadourian อาจไม่ ลองวัดถ้าคุณสังเกตเห็นปัญหาประสิทธิภาพการทำงานใด ๆ
Randy the Dev

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()แสดงให้เห็นว่ามีการเพิ่มองค์ประกอบหนึ่งโดยหนึ่งไปแต่สเปคไม่ได้รับประกันว่ามันจะเป็นHashSetHashSet

"ไม่มีการรับประกันกับประเภทความไม่แน่นอนความต่อเนื่องของอนุกรมหรือความปลอดภัยของเธรดของชุดที่ส่งคืน"

ดังนั้นจึงเป็นการดีกว่าที่จะใช้ตัวเลือกในภายหลัง ผลลัพธ์คือ: [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" และมันอ่านง่ายกว่า - ดีกว่าที่ใจของฉันถ้าคุณไม่ต้องการการรับประกันประเภทที่เป็นรูปธรรมความไม่แน่นอนความผันแปรของอนุกรมและความปลอดภัยของเธรด
Andrew Spencer

@AndrewSpencer Spec HashSetไม่ได้รับประกันว่าการดำเนินงานที่ตั้งไว้จะเป็น รับประกันได้เพียงว่ามันจะเป็นSetและนั่นคือสิ่งที่ฉันหมายถึง หวังว่าฉันจะชี้แจง
akhil_mittal

ขออภัยและขอบคุณฉันอ่านผิดเพราะความหมาย "สเป็คไม่รับประกันเพิ่มทีละคน" มากกว่า "สเป็คไม่ได้รับประกัน HashSet" เสนอให้มีการแก้ไขเพื่อชี้แจง
Andrew Spencer

19

หลังจากที่คุณทำArrays.asList(array)คุณสามารถดำเนินการSet set = new HashSet(list);

นี่คือวิธีตัวอย่างคุณสามารถเขียน:

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

ฉันหวังว่าวิธีที่คืนค่าชุดโดยตรงจากอาร์เรย์มีอยู่ไหม?

1
คุณสามารถเขียนของคุณเองถ้าคุณกระตือรือร้นมาก :)
Petar Minchev

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 Collections


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 สำหรับข้อมูลด้านบน
Ashley Frieze

5

มีการจำนวนมากของคำตอบที่ดีอยู่แล้ว แต่ส่วนใหญ่ของพวกเขาจะไม่ทำงานกับอาร์เรย์ของพื้นฐาน (เช่นint[], long[], char[], byte[]ฯลฯ )

ใน Java 8 ขึ้นไปคุณสามารถทำกล่องอาร์เรย์ด้วย:

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

จากนั้นแปลงเป็นชุดโดยใช้สตรีม:

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

0

บางครั้งการใช้ไลบรารีมาตรฐานบางอย่างช่วยได้มาก ลองไปดูที่Apache คอมมอนส์คอลเลกชัน ในกรณีนี้ปัญหาของคุณเปลี่ยนไปเป็นแบบนี้

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

และนี่คือCollectionsUtils javadoc


4
ผู้ใช้อาจไม่ใช้ apache ทั่วไป
Adrian

หากผู้ใช้ไม่ได้ใช้งาน apache ทั่วไปนั่นก็เป็นความผิดพลาดครั้งแรกของเขา
Jeryl Cook

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ส่งกลับ unmodifiable ที่มีองค์ประกอบของที่กำหนดSetCollection

 สิ่งที่ได้รับ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);' จาก java.util.Collections ใช้ตัววนซ้ำเดียวกัน แต่บวกการบูลีนหนึ่งครั้ง บวกกับ Bert F ชี้ให้เห็น Collections.addAll "น่าจะทำงานได้เร็วขึ้นอย่างมีนัยสำคัญภายใต้การใช้งานส่วนใหญ่" กว่า c.addAll (Arrays.asList (องค์ประกอบ))
Zorb

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.