Chuyển đổi Đặt thành Danh sách mà không tạo Danh sách mới


503

Tôi đang sử dụng mã này để chuyển đổi Setthành a List:

Map<String, List<String>> mainMap = new HashMap<>();

for (int i=0; i < something.size(); i++) {
  Set<String> set = getSet(...); //returns different result each time
  List<String> listOfNames = new ArrayList<>(set);
  mainMap.put(differentKeyName, listOfNames);
}

Tôi muốn tránh tạo một danh sách mới trong mỗi lần lặp của vòng lặp. Điều đó có thể không?


1
Tôi biết một cách để chuyển đổi được thiết lập thành danh sách như trong Q. Tôi muốn tránh việc tạo danh sách mới mỗi lần lặp.
Muhammad Imran Tariq

4
Tại sao bạn không thể thêm bộ vào mainList? Tại sao bạn cần chuyển đổi Tập hợp thành Danh sách?
DagR

1
Đây có phải là ý định của bạn để tạo Danh sách <Danh sách <? >>
Danh hiệu Hiery

5
Bạn không thể. Câu hỏi của bạn thể hiện một sự mâu thuẫn trong các điều khoản.
Hầu tước Lorne

Câu trả lời:


803

Bạn có thể sử dụng phương thức List.addAll () . Nó chấp nhận Bộ sưu tập làm đối số và bộ của bạn là Bộ sưu tập.

List<String> mainList = new ArrayList<String>();
mainList.addAll(set);

EDIT: như trả lời cho việc chỉnh sửa câu hỏi.
Dễ dàng thấy rằng nếu bạn muốn có a Mapvới Listcác giá trị, để có k giá trị khác nhau, bạn cần tạo k danh sách khác nhau.
Do đó: Bạn không thể tránh việc tạo các danh sách này, các danh sách sẽ phải được tạo.

Công việc có thể xảy ra:
Khai báo của bạn Mapnhư một Map<String,Set>hoặc Map<String,Collection>thay vào đó, và chỉ cần chèn bộ của bạn.


1
xin lỗi đó là mainMap không liệt kê. xem câu hỏi
Muhammad Imran Tariq

@imrantariq: là differentKeyNamethay đổi mỗi lần lặp? Bạn có thực sự muốn something.size()các giá trị khác nhau có thể có trong bản đồ của bạn? Dễ dàng thấy rằng một bản đồ với kcác danh sách là các giá trị cần tạo ít nhất là kcác danh sách.
amit

@imrantariq: và bạn muốn có một danh sách khác nhau cho mỗi khóa tôi giả sử?
amit

@imrantariq: Những gì bạn đang yêu cầu là không thể. đọc chỉnh sửa của tôi để biết thêm chi tiết.
amit

Nó sẽ trả về NullPulumException trong trường hợp set là null.
w35l3y

411

Sử dụng hàm tạo để chuyển đổi nó:

List<?> list = new ArrayList<?>(set);

21
Ông đặc biệt nói rằng ông muốn tránh điều này.
đồ

3
@mook Không liên quan, vì yêu cầu của anh ta không thể thực hiện được.
Hầu tước Lorne

16
@EJP thì câu trả lời của anh ta cần phải nói rằng, thay vì chỉ nêu ra điều gì đó mà OP không yêu cầu mà không có bất kỳ lời giải thích nào.
đồ

Anh ta tránh nó, hàm tạo đó sử dụng System.arrayCopy, tạo ra các bản sao nông, nghĩa là nó chỉ sao chép các tham chiếu của các đối tượng vào mảng được sử dụng để tạo danh sách. Nếu bạn so sánh cả hai bộ sưu tập, bạn sẽ thấy rằng cả hai đều chứa các tham chiếu đến cùng một đối tượng.
Gubatron

Điều này không thực sự hoạt động trên Android. Bất kỳ lý do tại sao?
kbluue

84

Cũng từ thư viện Guava Collection, bạn có thể sử dụng newArrayList(Collection):

Lists.newArrayList([your_set])

Điều này sẽ rất giống với câu trả lời trước đó từ amit , ngoại trừ việc bạn không cần phải khai báo (hoặc xúi giục) bất kỳ listđối tượng nào .


1
Nếu bạn đang sử dụng ổi, điều này rất tiện lợi
vsingh

6
Mặc dù bạn không trực tiếp gọi hàm tạo, phương thức này vẫn gọi hàm ArrayListtạo.
glen3b

Nếu tôi không khai báo Danh sách, làm cách nào tôi có thể sử dụng Danh sách được tạo?
Koray Tugay

@KorayTugay, bạn trích xuất Lists.newArrayList ([your_set]) trong một biến (cục bộ hoặc toàn cầu). Ví dụ: Danh sách <Foo> fooList = Lists.newArrayList (setOfFoo) Nhưng câu hỏi của bạn là thiếu sót. Nếu bạn tạo một danh sách, nó ít nhất được khai báo ngầm (nếu không rõ ràng).
chaiyachaiya

1
Bất kỳ đoán tại sao điều này làm cho phương pháp này? Nó dường như không tốt hơn new ArrayList<>([your_set]).
DavidS

49

Chúng ta có thể sử dụng một lớp lót sau trong Java 8:

List<String> list = set.stream().collect(Collectors.toList());

Đây là một ví dụ nhỏ:

public static void main(String[] args) {
        Set<String> set = new TreeSet<>();
        set.add("A");
        set.add("B");
        set.add("C");
        List<String> list = set.stream().collect(Collectors.toList());
}

7
Để dễ đọc, nó không được khuyến khích. Ví dụ: IntelliJ gợi ý "ArrayList mới <> (set)" và liệt kê hơn 20 mẫu mã tương tự có thể được thay thế theo cùng một cách.
rrhrg

chính xác! @rrhrg cái nào tốt hơn cho hiệu suất nếu chúng ta sử dụng set.poolStream ()?
bò tót

31

giải pháp đơn giản nhất

Tôi muốn một cách rất nhanh để chuyển đổi tập hợp của mình thành Danh sách và trả lại, vì vậy trong một dòng tôi đã làm

 return new ArrayList<Long>(mySetVariable);

1
Đây cũng là những gì IntelliJ IDEA gợi ý thay vì các luồng api.
Ben

6

Bạn có thể sử dụng thay đổi một dòng này: Arrays.asList(set.toArray(new Object[set.size()]))

Map<String, List> mainMap = new HashMap<String, List>();

for(int i=0; i<something.size(); i++){
  Set set = getSet(...); 
  mainMap.put(differentKeyName, Arrays.asList(set.toArray(new Object[set.size()])));
}  

Kích thước đã sửa vì Đối tượng mới [0] sẽ chỉ giữ một phần tử nhưng Đối tượng mới [set.size ()] sẽ giữ tất cả các giá trị
rajadilipkolli

5

Tôi sẽ làm :

Map<String, Collection> mainMap = new HashMap<String, Collection>();

for(int i=0; i<something.size(); i++){
  Set set = getSet(...); //return different result each time
  mainMap.put(differentKeyName,set);
}

5

Vì nó chưa được đề cập cho đến nay, kể từ Java 10, bạn có thể sử dụng copyOfphương thức nhà máy mới :

List.copyOf(set);

Từ Javadoc :

Trả về một Danh sách không thể thay đổi có chứa các thành phần của Bộ sưu tập đã cho, theo thứ tự lặp.


3

Java 8 cung cấp tùy chọn sử dụng các luồng và bạn có thể nhận được một danh sách từ Set<String> setString:

List<String> stringList = setString.stream().collect(Collectors.toList());

Mặc dù hiện tại việc triển khai nội bộ cung cấp một ví dụ về ArrayList:

public static <T>
    Collector<T, ?, List<T>> toList() {
        return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
                                   (left, right) -> { left.addAll(right); return left; },
                                   CH_ID);
    }

nhưng JDK không đảm bảo điều đó. Như đã đề cập ở đây :

Không có sự đảm bảo nào về loại, tính biến đổi, tính tuần tự hoặc tính an toàn của luồng của Danh sách được trả về; nếu cần thêm quyền kiểm soát Danh sách được trả về, hãy sử dụng toCollection (Nhà cung cấp).

Trong trường hợp bạn muốn chắc chắn luôn thì bạn có thể yêu cầu một ví dụ cụ thể như:

List<String> stringArrayList = setString.stream()
                     .collect(Collectors.toCollection(ArrayList::new));

2

Tôi tạo staticphương thức đơn giản :

public static <U> List<U> convertSetToList(Set<U> set)
{
    return new ArrayList<U>(set);
}

... hoặc nếu bạn muốn đặt loại Danh sách bạn có thể sử dụng:

public static <U, L extends List<U>> List<U> convertSetToList(Set<U> set, Class<L> clazz) throws InstantiationException, IllegalAccessException
{
    L list = clazz.newInstance();
    list.addAll(set);
    return list;
}

2

Gần đây tôi tìm thấy điều này:

ArrayList<T> yourList = Collections.list(Collections.enumeration(yourSet<T>));

1
Bạn có thể mở rộng hoặc xây dựng thêm về điều này?
Phá hoại

Bộ sưu public static <T> ArrayList<T> list(Enumeration<T> e) { ArrayList<T> l = new ArrayList<>(); while (e.hasMoreElements()) l.add(e.nextElement()); return l; }
tập.list

2

Vì lợi ích của sự hoàn chỉnh ...

Nói rằng bạn thực sự muốn coi các Mapgiá trị là Lists, nhưng bạn muốn tránh sao chép Setvào Listmỗi lần.

Chẳng hạn, có thể bạn đang gọi một hàm thư viện tạo ra một Set, nhưng bạn đang chuyển Map<String, List<String>>kết quả của mình sang hàm thư viện (được thiết kế kém nhưng nằm ngoài tầm tay) chỉ thực hiện Map<String, List<String>>, mặc dù bằng cách nào đó bạn biết rằng nó hoạt động với Lists được áp dụng như nhau cho bất kỳ Collection(và do đó bất kỳ Set). Và vì một số lý do, bạn cần tránh tốc độ / chi phí bộ nhớ khi sao chép từng Set thành Danh sách.

Trong trường hợp siêu thích hợp này, tùy thuộc vào hành vi (có thể không thể biết) mà chức năng thư viện cần từ bên ngoài của bạn List, bạn có thể tạo List chế độ xem qua mỗi Bộ. Lưu ý rằng điều này vốn không an toàn (vì các yêu cầu của chức năng thư viện Listcó thể thay đổi mà bạn không biết), vì vậy nên sử dụng giải pháp khác. Nhưng đây là cách bạn làm điều đó.

Bạn sẽ tạo một lớp thực hiện Listgiao diện, lấy một Sethàm tạo và gán Set đó cho một trường, sau đó sử dụng nội bộ đó Setđể triển khai ListAPI (trong phạm vi có thể và mong muốn).

Lưu ý rằng một số hành vi Danh sách mà bạn đơn giản sẽ không thể bắt chước mà không lưu trữ các phần tử dưới dạng Listvà một số hành vi bạn sẽ chỉ có thể bắt chước một phần. Một lần nữa, lớp này không phải là sự thay thế thả vào an toàn cho Lists nói chung. Đặc biệt, nếu bạn biết rằng ca sử dụng yêu cầu các hoạt động liên quan đến chỉ mục hoặc MUTATING List, cách tiếp cận này sẽ đi về phía nam rất nhanh.

public class ListViewOfSet<U> implements List<U> {
    private final Set<U> wrappedSet;
    public ListViewOfSet(Set<U> setToWrap) { this.wrappedSet = setToWrap; }

    @Override public int size() { return this.wrappedSet.size(); }
    @Override public boolean isEmpty() { return this.wrappedSet.isEmpty(); }
    @Override public boolean contains(Object o) { return this.wrappedSet.contains(o); }
    @Override public java.util.Iterator<U> iterator() { return this.wrappedSet.iterator(); }
    @Override public Object[] toArray() { return this.wrappedSet.toArray(); }
    @Override public <T> T[] toArray(T[] ts) { return this.wrappedSet.toArray(ts); }
    @Override public boolean add(U e) { return this.wrappedSet.add(e); }
    @Override public boolean remove(Object o) { return this.wrappedSet.remove(o); }
    @Override public boolean containsAll(Collection<?> clctn) { return this.wrappedSet.containsAll(clctn); }
    @Override public boolean addAll(Collection<? extends U> clctn) { return this.wrappedSet.addAll(clctn); }
    @Override public boolean addAll(int i, Collection<? extends U> clctn) { throw new UnsupportedOperationException(); }
    @Override public boolean removeAll(Collection<?> clctn) { return this.wrappedSet.removeAll(clctn); }
    @Override public boolean retainAll(Collection<?> clctn) { return this.wrappedSet.retainAll(clctn); }
    @Override public void clear() { this.wrappedSet.clear(); }
    @Override public U get(int i) { throw new UnsupportedOperationException(); }
    @Override public U set(int i, U e) { throw new UnsupportedOperationException(); }
    @Override public void add(int i, U e) { throw new UnsupportedOperationException(); }
    @Override public U remove(int i) { throw new UnsupportedOperationException(); }
    @Override public int indexOf(Object o) { throw new UnsupportedOperationException(); }
    @Override public int lastIndexOf(Object o) { throw new UnsupportedOperationException(); }
    @Override public ListIterator<U> listIterator() { throw new UnsupportedOperationException(); }
    @Override public ListIterator<U> listIterator(int i) { throw new UnsupportedOperationException(); }
    @Override public List<U> subList(int i, int i1) { throw new UnsupportedOperationException(); }
}

...
Set<String> set = getSet(...);
ListViewOfSet<String> listOfNames = new ListViewOfSet<>(set);
...

Đây thực sự là câu trả lời duy nhất thực sự giải quyết được vấn đề đã nêu trong câu hỏi!
Lii

Bạn có thể thực hiện điều này khá dễ dàng bằng cách mở rộng AbstractList
Lii

1

Tôi thấy điều này hoạt động tốt và hữu ích để tạo Danh sách từ Tập hợp.

ArrayList < String > L1 = new ArrayList < String > ();
L1.addAll(ActualMap.keySet());
for (String x: L1) {
    System.out.println(x.toString());
}

-15
Map<String, List> mainMap = new HashMap<String, List>();

for(int i=0; i<something.size(); i++){
  Set set = getSet(...); //return different result each time
  mainMap.put(differentKeyName, new ArrayList(set));
}

11
Bạn đã không tránh việc tạo danh sách. Mã này tương tự như mẫu trong câu hỏi của bạn.
Taylor

2
Nhưng nó không trả lời câu hỏi của bạn, không phải là có câu trả lời.
Hầu tước Lorne
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.