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

发布于 2024-12-27 15:51:59 字数 420 浏览 1 评论 0 原文

我正在使用此代码将 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);
}

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

I am using this code to convert a Set to 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);
}

I want to avoid creating a new list in each iteration of the loop. Is that possible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(15

樱花细雨 2025-01-03 15:51:59

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

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

编辑:作为对问题编辑的回应。

很容易看出,如果你想要一个以List作为值的Map,为了有k个不同的值,你需要创建k个不同的值列表。

因此:您根本无法避免创建这些列表,必须创建这些列表。

可能的解决方法:

将您的 Map 声明为 MapMap,然后插入您的集合。

You can use the List.addAll() method. It accepts a Collection as an argument, and your set is a Collection.

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

EDIT: as respond to the edit of the question.

It is easy to see that if you want to have a Map with Lists as values, in order to have k different values, you need to create k different lists.

Thus: You cannot avoid creating these lists at all, the lists will have to be created.

Possible work around:

Declare your Map as a Map<String,Set> or Map<String,Collection> instead, and just insert your set.

南…巷孤猫 2025-01-03 15:51:59

使用构造函数来转换它:

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

Use constructor to convert it:

List<?> list = new ArrayList<>(set);
So尛奶瓶 2025-01-03 15:51:59

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

Lists.newArrayList([your_set])

这与 amit 之前的答案非常相似,只是您不需要声明(或实例化)任何list对象。

Also from Guava Collect library, you can use newArrayList(Collection):

Lists.newArrayList([your_set])

This would be very similar to the previous answer from amit, except that you do not need to declare (or instanciate) any list object.

一场春暖 2025-01-03 15:51:59

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

注意: 这种使用流创建的方式会产生内存损失。如果需要避免创建新内存,则避免使用此解决方案

We can use following one liner in Java 8:

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

Here is one small example:

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

Note: This way of creating using streams has a memory penalty. If need is to avoid creating new memory, then avoid this solution

川水往事 2025-01-03 15:51:59

最简单的解决方案

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

 return new ArrayList<Long>(mySetVariable);

the simplest solution

I wanted a very quick way to convert my set to List and return it, so in one line I did

 return new ArrayList<Long>(mySetVariable);
一片旧的回忆 2025-01-03 15:51:59

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

List.copyOf(set);

来自 Javadoc

返回一个不可修改的列表包含给定 Collection 的元素(按其迭代顺序)。

请注意,这会创建一个新列表(ImmutableCollections$ListN 准确地说,通过在

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

Since it hasn't been mentioned so far, as of Java 10 you can use the new copyOf factory method:

List.copyOf(set);

From the Javadoc:

Returns an unmodifiable List containing the elements of the given Collection, in its iteration order.

Note that this creates a new list (ImmutableCollections$ListN to be precise) under the hood by

  1. calling Collection#toArray() on the given set and then
  2. putting these objects into a new array.
悲歌长辞 2025-01-03 15:51:59

为了完整起见......

假设您确实确实希望将Map值视为List,但您希望避免复制每次将 Set 放入 List 中。

例如,也许您正在调用一个创建 Set 的库函数,但您将 Map> 结果传递给一个(很差-设计但不在你手中)只需要 Map> 的库函数,即使你以某种方式知道它对List 同样适用于任何Collection(因此也适用于任何Set)。 由于某种原因,您需要避免将每个集合复制到列表的速度/内存开销。

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

您将创建一个实现 List 接口的类,在构造函数中采用 Set 并将该 Set 分配给一个字段,然后使用该内部 Set< /code> 实现 List API(在可能的情况下和需要的范围内)。

请注意,如果不将元素存储为 List,您将无法模仿某些列表行为,而您只能部分模仿某些行为。同样,一般来说,此类并不是 List 的安全替代品。特别是,如果您知道用例需要与索引相关的操作或修改 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);
...

For the sake of completeness...

Say that you really do want to treat the Map values as Lists, but you want to avoid copying the Set into a List each time.

For instance, maybe you are calling one library function that creates a Set, but you are passing your Map<String, List<String>> result to a (poorly-designed but out of your hands) library function that only takes Map<String, List<String>>, even though somehow you know that the operations it does with the Lists are equally applicable to any Collection (and thus any Set). And for some reason you need to avoid the speed/memory overhead of copying each Set to a List.

In this super niche case, depending on the (maybe unknowable) behavior the library function needs out of your Lists, you may be able to create a List view over each Set. Note that this is inherently unsafe (because the library function's requirements from each List could presumably change without you knowing), so another solution should be preferred. But here's how you'd do it.

You'd create a class that implements the List interface, takes a Set in the constructor and assigns that Set to a field, and then uses that internal Set to implement the List API (to the extent possible, and desired).

Note that some List behavior you simply will not be able to imitate without storing the elements as a List, and some behavior you will only partially be able to imitate. Again, this class is not a safe drop-in replacement for Lists in general. In particular, if you know that the use case requires index-related operations or MUTATING the List, this approach would go south very fast.

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);
...
送君千里 2025-01-03 15:51:59

我会这样做:

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

I would do :

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);
}
眼藏柔 2025-01-03 15:51:59

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

You could use this one line change: 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()])));
}  
赠佳期 2025-01-03 15:51:59

Java 8 提供了使用流的选项,您可以从 Set 获取列表。 setString as:

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并不保证它。正如这里提到的

不保证类型、可变性、可序列化性或
返回的列表的线程安全;如果对返回的有更多控制
列表为必填项,请使用 toCollection(Supplier)。

如果您想始终确保,那么您可以专门请求一个实例,如下所示:

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

Java 8 provides the option of using streams and you can get a list from Set<String> setString as:

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

Though the internal implementation as of now provides an instance of 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);
    }

but JDK does not guarantee it. As mentioned here:

There are no guarantees on the type, mutability, serializability, or
thread-safety of the List returned; if more control over the returned
List is required, use toCollection(Supplier).

In case you want to be sure always then you can request for an instance specifically as:

List<String> stringArrayList = setString.stream()
                     .collect(Collectors.toCollection(ArrayList::new));
极致的悲 2025-01-03 15:51:59

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

I create simple static method:

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

... or if you want to set type of List you can use:

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;
}
北风几吹夏 2025-01-03 15:51:59

最近我发现了这个:

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

Recently I found this:

ArrayList<T> yourList = Collections.list(Collections.enumeration(yourSet<T>));
柳絮泡泡 2025-01-03 15:51:59

我发现这工作正常并且对于从集合创建列表很有用。

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

I found this working fine and useful to create a List from a Set.

ArrayList < String > L1 = new ArrayList < String > ();
L1.addAll(ActualMap.keySet());
for (String x: L1) {
    System.out.println(x.toString());
}
ら栖息 2025-01-03 15:51:59

您可以将 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);
}

免责声明:我对类似答案的编辑被拒绝,因此我添加了自己的答案以及其他信息< /em>


You convert Set to List without adding ordering information (like sorting) just to store it in the map.

Because Set is unordered and no ordering information is added, List should not be used, as it will contain randomly ordered data and all it's methods that are related to ordered data will be ambiguous.

You should use Collection interface instead, that accepts both Set and List in the map. This way, no additional memory is required as you use polymorphism instead of copying data.

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

Disclaimer: my edit to a similar answer was rejected so I added my own answer with additional information

堇年纸鸢 2025-01-03 15:51:59
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));
}
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));
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文