将集转换为列表而不创建新列表


503

我正在使用此代码将转换SetList

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

我想避免在循环的每次迭代中创建一个新列表。那可能吗?


1
我知道一种将集合转换为列表的方法,如Q。我想避免每次循环都创建新列表。
穆罕默德·伊姆兰·塔里克

4
为什么不能只将集合添加到mainList?为什么需要将Set转换为List?
DagR 2012年

1
您是否打算创建List <List <?>>
Hiery Nomus 2012年

5
你不能 您的问题体现出术语上的矛盾。
罗恩侯爵

Answers:


802

您可以使用List.addAll()方法。它接受Collection作为参数,而您的集合就是Collection。

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

编辑:作为对问题的编辑的回应。
很容易看出,如果要使用Map带有Lists的值,则要具有k个不同的值,则需要创建k个不同的列表。
因此:您完全无法避免创建这些列表,必须创建列表。

可能的解决方法:
声明您Map为a Map<String,Set>Map<String,Collection>代替,然后插入您的集合。


1
抱歉,它不是mainMap列表。看到问题
穆罕默德·伊姆兰·塔里克

@imrantariq:differentKeyName每次迭代都会更改吗?您实际上是否要something.size()在地图中使用其他可能的值?显而易见,以k列表为值的地图至少需要创建k列表。
2012年

@imrantariq:您想为我假设的每个键使用不同的列表吗?
2012年

@imrantariq:您要的是不可能的。阅读我的编辑以获取更多详细信息。
2012年

如果set为null,它将返回NullPointerException。
w35l3y

411

使用构造函数进行转换:

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

21
他特别表示希望避免这种情况。
mapeters '16

3
@mook不相关,因为他的要求无法实现。
罗恩侯爵

16
@EJP然后他的答案需要说,而不是简单地陈述OP在没有任何解释的情况下所要求的内容。
mapeters'8

他避免这样做,构造函数使用System.arrayCopy进行浅拷贝,这意味着,它仅将对象的引用复制到用于创建列表的数组中。如果比较两个集合,您将看到它们都包含对相同对象的引用。
古巴创'16

这实际上不适用于Android。有什么原因吗?
kbluue

84

同样从Guava Collect库中,您可以使用newArrayList(Collection)

Lists.newArrayList([your_set])

这与amit的先前答案非常相似,不同之处在于您无需声明(或实例化)任何list对象。


1
如果您使用的是番石榴,这将非常方便
vsingh 2013年

6
尽管您没有直接调用构造函数,但此方法仍会调用ArrayList构造函数。
glen3b 2014年

如果未声明列表,如何使用创建的列表?
Koray Tugay 2014年

@KorayTugay,那么您可以在一个变量(本地或全局)中提取Lists.newArrayList([your_set])。例如:List <Foo> fooList = Lists.newArrayList(setOfFoo)但是您的问题有缺陷。如果创建列表,则至少会隐式声明(如果未显式声明)。
chaiyachaiya

1
关于为什么使用此方法的任何猜测?似乎没有比这更好的了new ArrayList<>([your_set])
DavidS

48

我们可以在Java 8中使用以下一种内联代码:

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

这是一个小例子:

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
为了便于阅读,不建议这样做。例如,IntelliJ建议使用“ new ArrayList <>(set)”,并列出可以使用相同方式替换的20多个类似代码示例。
rrrrg

究竟!@rrhrg如果使用set.parallelStream()哪个性能更好?
gaurav

31

最简单的解决方案

我想要一种非常快速的方法来将我的集合转换为List并返回它,所以我做了一行

 return new ArrayList<Long>(mySetVariable);

1
这也是IntelliJ IDEA而不是stream api所建议的。

6

您可以使用这一行更改: 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()])));
}  

更正了大小,因为新的Object [0]仅包含一个元素,而新的Object [set.size()]将包含所有值
rajadilipkolli

5

我会做 :

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

4

由于到目前为止尚未提及它,因此从Java 10开始,您可以使用新的copyOf工厂方法:

List.copyOf(set);

Javadoc

以迭代顺序返回包含给定Collection元素的不可修改List


3

Java 8提供了使用流的选项,您可以通过以下方式获取列表Set<String> setString

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

尽管目前的内部实现提供了以下实例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);
    }

但是JDK不能保证。如前所述这里

无法保证返回的List的类型,可变性,可序列化性或线程安全性;如果需要对返回的List进行更多控制,请使用toCollection(Supplier)。

如果您想始终确定,则可以请求一个实例,具体如下:

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

2

我创建简单的static方法:

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

...或者如果您想设置列表类型,可以使用:

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

最近我发现了这个:

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

1
您可以对此进行扩展或详细说明吗?
Vandal

Collections.list()创建一个新的ArrayList:public static <T> ArrayList<T> list(Enumeration<T> e) { ArrayList<T> l = new ArrayList<>(); while (e.hasMoreElements()) l.add(e.nextElement()); return l; }
Artem Lukanin

2

为了完整性...

假设您确实确实希望将Map值视为Lists,但您要避免每次都将其复制Set到中List

例如,也许您正在调用一个创建的库函数Set,但是您将Map<String, List<String>>结果传递给仅需要的(设计欠佳但不易使用)库函数Map<String, List<String>>,即使您以某种方式知道它对Lists同样适用于任何Collection(因此任何Set)。并且由于某些原因,您需要避免将每个Set复制到列表的速度/内存开销。

在这种特殊情况下,根据库函数需要使用的行为(可能是未知的)List,您可能可以在每个Set 上创建一个List 视图。请注意,这本质上是不安全的(因为每个库函数的要求List可能会在您不知情的情况下发生变化),因此应首选其他解决方案。但是,这是您的处理方式。

您将创建一个实现该List接口的类,Set在构造函数中使用a并将该Set分配给一个字段,然后使用该内部Set实现ListAPI(在可能和期望的范围内)。

请注意,某些List行为如果不将元素存储为List,就无法模仿,而某些行为则只能部分模仿。同样,此类通常不是Lists 的安全替代。特别是,如果您知道用例需要进行与索引相关的操作或MUTATING List,则此方法将很快发展。

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

这实际上是解决问题中所述问题的唯一答案!
Lii

您可以通过扩展AbstractList
Lii

1

我发现此方法很好用,并且可以从集合创建列表。

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
您一直在避免创建列表。这段代码与问题中的示例非常相似。
泰勒

2
但这并不能回答您的quezon,也不是有答案。
罗恩侯爵
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.