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
.
This question is related to
java
list
sorting
collections
apache-commons-collection
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);
@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());
}
Something like this should work, calling the ArrayList constructor that takes a Collection:
List theList = new ArrayList(coll);
Use streams:
someCollection.stream().collect(Collectors.toList())
Collections.sort( new ArrayList( coll ) );
Here is a sub-optimal solution as a one-liner:
Collections.list(Collections.enumeration(coll));
I believe you can write it as such:
coll.stream().collect(Collectors.toList())
Java 10 introduced List#copyOf
which returns unmodifiable List while preserving the order:
List<Integer> list = List.copyOf(coll);
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.
Source: Stackoverflow.com