Reputation: 23352
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?
Upvotes: 625
Views: 1155875
Reputation: 3601
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
Upvotes: 58
Reputation: 5313
Use constructor to convert it:
List<?> list = new ArrayList<>(set);
Upvotes: 509
Reputation: 9443
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
Collection#toArray()
on the given set and thenUpvotes: 23
Reputation: 1561
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
Upvotes: 0
Reputation: 199
For the sake of completeness...
Say that you really do want to treat the Map
values as List
s, 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 List
s 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 List
s, 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 List
s 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);
...
Upvotes: 8
Reputation: 178521
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 List
s 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.
Upvotes: 920
Reputation: 15367
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);
Upvotes: 46
Reputation: 47
Recently I found this:
ArrayList<T> yourList = Collections.list(Collections.enumeration(yourSet<T>));
Upvotes: 2
Reputation: 24167
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));
Upvotes: 4
Reputation: 2717
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.
Upvotes: 94
Reputation: 9418
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()])));
}
Upvotes: 5
Reputation: 136
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;
}
Upvotes: 3
Reputation: 436
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());
}
Upvotes: 0
Reputation: 23352
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));
}
Upvotes: -16
Reputation: 637
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);
}
Upvotes: 5