将Set转换为List而不创建新List

Muh*_*riq 478 java performance list set

我使用此代码将a转换SetList:

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

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

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

ami*_*mit 769

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

List<String> mainList = new ArrayList<String>();
mainList.addAll(set);
Run Code Online (Sandbox Code Playgroud)

编辑:响应编辑问题.
很容易看出,如果你想Map使用Lists作为值,为了得到k个不同的值,你需要创建k个不同的列表.
因此:您根本无法避免创建这些列表,必须创建列表.

可能的解决方法:
将您声明MapMap<String,Set>Map<String,Collection>替换,然后插入您的集合.


小智 401

使用构造函数转换它:

List<?> list = new ArrayList<?>(set);
Run Code Online (Sandbox Code Playgroud)

  • 他特意说他想避免这种情况. (17认同)
  • @EJP然后他的回答需要说,而不是简单地陈述OP没有任何解释的要求. (13认同)
  • @mook不相关,因为他的要求不可实现. (2认同)
  • 他正在避免它,该构造函数使用 System.arrayCopy,它进行浅拷贝,这意味着它只将对象的引用复制到用于创建列表的数组中。如果比较两个集合,您会发现它们都包含对相同对象的引用。 (2认同)

cha*_*iya 80

同样来自Guava Collect库,您可以使用newArrayList(Collection):

Lists.newArrayList([your_set])
Run Code Online (Sandbox Code Playgroud)

这与amit的前一个答案非常相似,只是您不需要声明(或instanciate)任何list对象.

  • 虽然您没有直接调用构造函数,但此方法仍然调用`ArrayList`构造函数. (5认同)
  • 如果您使用番石榴,这很方便 (2认同)
  • 关于为什么会采用这种方法的任何猜测?它似乎并不比`new ArrayList&lt;&gt;([your_set])`更好。 (2认同)

raj*_*lli 38

我们可以在Java 8中使用以下一个线程:

List<String> list = set.stream().collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

这是一个小例子:

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());
}
Run Code Online (Sandbox Code Playgroud)

  • 为了便于阅读,不建议这样做.例如,IntelliJ建议"new ArrayList <>(set)"并列出20多个类似的代码示例,可以用相同的方式替换. (5认同)
  • 直到今天,我不知道这个评论是如何获得如此多的赞成票的,尤其是在做一件简单的事情时,但正如其他评论指出的那样,事情变得更加复杂。此外,它还创建了一个新列表,这是作者试图避免的。 (3认同)

Bas*_*ANI 24

最简单的解决方案

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

 return new ArrayList<Long>(mySetVariable);
Run Code Online (Sandbox Code Playgroud)


bea*_*u13 8

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

List.copyOf(set);
Run Code Online (Sandbox Code Playgroud)

Javadoc

返回一个不可修改的 List,其中包含给定 Collection 的元素,按其迭代顺序。

请注意,这会ImmutableCollections$ListN在引擎盖下创建一个新列表(准确地说)

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

  • 不幸的是,“List.copyOf”仍然分配一个新的内存区域来存储项目。 (3认同)

Sah*_*eed 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()])));
}  
Run Code Online (Sandbox Code Playgroud)


Dan*_*ery 6

为了完整起见...

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

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

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

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

请注意,如果不将元素存储为 a ,您将无法模仿某些 List 行为List,而有些行为您将只能部分模仿。List再次强调,这个类一般来说并不是 s 的安全替代品。特别是,如果您知道用例需要与索引相关的操作或对 进行 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);
...
Run Code Online (Sandbox Code Playgroud)

  • 这实际上是真正解决问题中所述问题的唯一答案! (2认同)

小智 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);
}
Run Code Online (Sandbox Code Playgroud)