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
.
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);
Something like this should work, calling the ArrayList constructor that takes a Collection:
List theList = new ArrayList(coll);
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);
I believe you can write it as such:
coll.stream().collect(Collectors.toList())
Collections.sort( new ArrayList( coll ) );
@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());
}
What you request is quite a costy operation, make sure you don't need to do it often (e.g in a cycle).
Otherwise, you can create a custom collection. 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 keySet() {
return map.keySet();
}
public Multiset values() {
return multiset;
}
// many more methods to be implemented, e.g. count, isEmpty etc.
}
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 have to invent something more complex.
Here is a sub-optimal solution as a one-liner:
Collections.list(Collections.enumeration(coll));