在不创建新列表的情况下将Set转换为List

我使用这段代码将Set转换为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);
}

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

1042754 次浏览

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

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

编辑:作为对问题编辑的响应。 很容易看出,如果你想有一个MapLists作为值,为了有k个不同的值,你需要创建k个不同的列表。
因此:您根本无法避免创建这些列表,必须创建这些列表。

可能的工作方式:
Map声明为Map<String,Set>Map<String,Collection>,然后插入你的集合。

我会这样做:

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

同样从Guava收集库,你可以使用newArrayList(Collection):

Lists.newArrayList([your_set])

这将非常类似于前面来自阿米特的答案,除了您不需要声明(或实例化)任何list对象。

使用构造函数转换它:

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

我发现这工作很好,有用的从一个集合创建一个列表。

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

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

我创建了简单的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;
}

我们可以在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());
}

最近我发现了这个:

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

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

最简单的解决方案

我想要一种非常快速的方法将我的set转换为List并返回它,所以在一行中我做到了

 return new ArrayList<Long>(mySetVariable);

为了完整起见……

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

例如,也许你正在调用一个创建Set的库函数,但是你正在将你的Map<String, List<String>>结果传递给一个只接受Map<String, List<String>>的库函数(设计很差,但不是你能控制的),尽管它对# eyz3所做的操作同样适用于任何Collection(因此也适用于任何Set)。出于某种原因你需要避免复制每个Set到List的速度/内存开销。

在这种超级小的情况下,根据库函数需要从Lists中获得的行为(可能是不可知的),您可以在每个Set上创建List 视图。注意,这本质上是不安全的(因为每个List的库函数的需求可能会在您不知道的情况下发生变化),因此应该首选另一种解决方案。但你可以这样做。

您将创建一个实现List接口的类,在构造函数中接受Set并将该Set赋值给一个字段,然后使用内部的Set来实现List API(在可能和需要的范围内)。

请注意,有些List行为如果不将元素存储为List就无法模仿,有些行为只能部分模仿。同样,这个类通常不是Lists的安全替代品。特别是,如果您知道用例需要索引相关的操作或对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);
...

由于到目前为止还没有提到它,从Java 10开始,你可以使用新的copyOf工厂方法:

List.copyOf(set);

Javadoc:

按迭代顺序返回包含给定Collection元素的无法改变的列表

注意,这将创建一个新列表(确切地说是ImmutableCollections$ListN)在引擎盖下由

  1. 在给定集合上调用Collection#toArray(),然后
  2. 将这些对象放入一个新数组中。

Set转换为List而不添加排序信息(如排序),只是为了将其存储在映射中。

因为Set是无序的,没有添加任何排序信息,所以不应该使用List,因为它将包含随机有序的数据,并且它的所有与有序数据相关的方法都是不明确的。

你应该使用Collection接口代替,它在地图中接受SetList。这样,就不需要额外的内存,因为您使用多态而不是复制数据。

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


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

免责声明:我对类似答案的编辑被拒绝了,所以我添加了自己的答案和其他信息