Reputation: 51100
I am using TreeBidiMap
from the Apache Collections library. I want to sort this on the values which are doubles
.
My method is to retrieve a Collection
of the values using:
Collection coll = themap.values();
Which naturally works fine.
Main Question: I now want to know how I can convert/cast (not sure which is correct) coll
into a List
so it can be sorted?
I then intend to iterate over the sorted List
object, which should be in order and get the appropriate keys from the TreeBidiMap
(themap
) using themap.getKey(iterator.next())
where the iterator will be over the list of doubles
.
Upvotes: 354
Views: 678444
Reputation: 2534
Java 8 onwards...
You can convert Collection to any collection (i.e, List, Set, and Queue) using Streams and Collectors.toCollection().
Consider the following example map
Map<Integer, Double> map = Map.of(
1, 1015.45,
2, 8956.31,
3, 1234.86,
4, 2348.26,
5, 7351.03
);
to ArrayList
List<Double> arrayList = map.values()
.stream()
.collect(
Collectors.toCollection(ArrayList::new)
);
Output: [7351.03, 2348.26, 1234.86, 8956.31, 1015.45]
to Sorted ArrayList (Ascending order)
List<Double> arrayListSortedAsc = map.values()
.stream()
.sorted()
.collect(
Collectors.toCollection(ArrayList::new)
);
Output: [1015.45, 1234.86, 2348.26, 7351.03, 8956.31]
to Sorted ArrayList (Descending order)
List<Double> arrayListSortedDesc = map.values()
.stream()
.sorted(
(a, b) -> b.compareTo(a)
)
.collect(
Collectors.toCollection(ArrayList::new)
);
Output: [8956.31, 7351.03, 2348.26, 1234.86, 1015.45]
to LinkedList
List<Double> linkedList = map.values()
.stream()
.collect(
Collectors.toCollection(LinkedList::new)
);
Output: [7351.03, 2348.26, 1234.86, 8956.31, 1015.45]
to HashSet
Set<Double> hashSet = map.values()
.stream()
.collect(
Collectors.toCollection(HashSet::new)
);
Output: [2348.26, 8956.31, 1015.45, 1234.86, 7351.03]
to PriorityQueue
PriorityQueue<Double> priorityQueue = map.values()
.stream()
.collect(
Collectors.toCollection(PriorityQueue::new)
);
Output: [1015.45, 1234.86, 2348.26, 8956.31, 7351.03]
Reference
Java - Package java.util.stream
Upvotes: 7
Reputation: 546
Use streams:
someCollection.stream().collect(Collectors.toList())
Upvotes: 0
Reputation: 12937
Java 10 introduced List#copyOf
which returns unmodifiable List while preserving the order:
List<Integer> list = List.copyOf(coll);
Upvotes: 17
Reputation: 5546
What you request is quite a costy operation, make sure you don't need to do it often (e.g in a cycle).
If you need it to stay sorted and you update it frequently, you can create a custom collection. For example, I came up with one that has your TreeBidiMap
and TreeMultiset
under the hood. Implement only what you need and care about data integrity.
class MyCustomCollection implements Map<K, V> {
TreeBidiMap<K, V> map;
TreeMultiset<V> multiset;
public V put(K key, V value) {
removeValue(map.put(key, value));
multiset.add(value);
}
public boolean remove(K key) {
removeValue(map.remove(key));
}
/** removes value that was removed/replaced in map */
private removeValue(V value) {
if (value != null) {
multiset.remove(value);
}
}
public Set<K> keySet() {
return Collections.unmodifiableSet(map.keySet());
}
public Collection<V> values() {
return Collections.unmodifiableCollection(multiset);
}
// many more methods to be implemented, e.g. count, isEmpty etc.
// but these are fairly simple
}
This way, you have a sorted Multiset
returned from values()
. However, if you need it to be a list (e.g. you need the array-like get(index)
method), you'd need something more complex.
For brevity, I only return unmodifiable collections. What @Lino mentioned is correct, and modifying the keySet
or values
collection as it is would make it inconsistent. I don't know any consistent way to make the values
mutable, but the keySet
could support remove
if it uses the remove
method from the MyCustomCollection
class above.
Upvotes: 1
Reputation: 700
I believe you can write it as such:
coll.stream().collect(Collectors.toList())
Upvotes: 36
Reputation: 22487
Something like this should work, calling the ArrayList constructor that takes a Collection:
List theList = new ArrayList(coll);
Upvotes: 116
Reputation: 103
Here is a sub-optimal solution as a one-liner:
Collections.list(Collections.enumeration(coll));
Upvotes: -5
Reputation: 534
@Kunigami: I think you may be mistaken about Guava's newArrayList
method. It does not check whether the Iterable is a List type and simply return the given List as-is. It always creates a new list:
@GwtCompatible(serializable = true)
public static <E> ArrayList<E> newArrayList(Iterable<? extends E> elements) {
checkNotNull(elements); // for GWT
// Let ArrayList's sizing logic work, if possible
return (elements instanceof Collection)
? new ArrayList<E>(Collections2.cast(elements))
: newArrayList(elements.iterator());
}
Upvotes: 4
Reputation: 182782
List list = new ArrayList(coll);
Collections.sort(list);
As Erel Segal Halevi says below, if coll is already a list, you can skip step one. But that would depend on the internals of TreeBidiMap.
List list;
if (coll instanceof List)
list = (List)coll;
else
list = new ArrayList(coll);
Upvotes: 528
Reputation: 36745
I think Paul Tomblin's answer may be wasteful in case coll is already a list, because it will create a new list and copy all elements. If coll contains many elemeents, this may take a long time.
My suggestion is:
List list;
if (coll instanceof List)
list = (List)coll;
else
list = new ArrayList(coll);
Collections.sort(list);
Upvotes: 34