Как преобразовать коллекцию в список?

294

Я использую TreeBidiMapиз библиотеки Apache Collections . Я хочу отсортировать это по значениям, которые есть doubles.

Мой метод заключается в получении Collectionзначений с помощью:

Collection coll = themap.values();

Что естественно работает нормально.

Главный вопрос: теперь я хочу знать, как я могу преобразовать / привести (не уверен, что это правильно) collв Listтак, чтобы он мог быть отсортирован?

Затем я собираюсь перебрать отсортированный Listобъект, который должен быть в порядке, и получить соответствующие ключи из TreeBidiMap( themap), используя, themap.getKey(iterator.next())где итератор будет над списком doubles.

Анкур
источник
4
Возможно, вы захотите избежать этого шага, напрямую используя какой-то SortedMap, чтобы записи были в естественном порядке используемых ключей. Собственный Java TreeMap реализует SortedMap.
Аксель Кнауф
TreeBidiMapэто OrderedMap, порядок должен быть в порядке. Требуемая сортировка в вопросе - по значениям, а не по ключам.
Власек

Ответы:

470
List list = new ArrayList(coll);
Collections.sort(list);

Как говорит Erel Segal Halevi ниже, если coll уже список, вы можете пропустить первый шаг. Но это будет зависеть от внутренних компонентов TreeBidiMap.

List list;
if (coll instanceof List)
  list = (List)coll;
else
  list = new ArrayList(coll);
Пол Томблин
источник
4
Просто отметим, что у этих двух подходов есть разные побочные эффекты: приведение коллекции к списку, а затем сортировка также отсортирует исходную коллекцию; создавать копии не буду.
Барни
Такой подход значительно снижает производительность, если используется повторно. Смотрите мой ответ для решения, которое работает на лету, оно включает в себя собственную коллекцию.
Власек
Это не разрешает случай, когда map.values ​​() возвращает коллекцию «внутреннего класса». Компилятор сообщает, что Collections.sort (List <T>) не принимает Collections.sort (List <InnerClass>). Решение было даже использовать: List <InnerClass> list = map.values ​​(). Stream (). Collect (Collectors.toList ())
Перейра
92

Нечто подобное должно работать, вызывая конструктор ArrayList, который принимает коллекцию:

List theList = new ArrayList(coll);
Джек Леу
источник
Красиво и просто.
Джеймс Гаврон
33

Я думаю, что ответ Пола Томблина может быть расточительным, если coll - это уже список, потому что он создаст новый список и скопирует все элементы. Если в coll содержится много элементов, это может занять много времени.

Мое предложение:

List list;
if (coll instanceof List)
  list = (List)coll;
else
  list = new ArrayList(coll);
Collections.sort(list);
Эрель Сегал-Халеви
источник
21

Я считаю, что вы можете написать это так:

coll.stream().collect(Collectors.toList())
Эяль Офри
источник
Лучший способ обойти кастинг
Stackee007
Большой! Это решило мое дело. Мой map.values ​​() возвращает коллекцию "внутренний класс". Компилятор сообщил, что Collections.sort (List <T>) не принимает Collections.sort (List <InnerClass>).
Перейра
не работал для моего варианта использования в Android. требуется минимум 24 api
ansh sachdeva
8
Collections.sort( new ArrayList( coll ) );
OscarRyz
источник
Отсутствует ссылка для доступа к ArrayList?
Зак Скривена
@ Зак: ммхх хорошая мысль. Я знал, что у меня была причина отметить это как CW. Кстати, Пол Анс Я не знаю, почему у него только мой уф.
OscarRyz
4

@Kunigami: Думаю, вы ошибаетесь в newArrayListметоде Гуавы . Он не проверяет, является ли Iterable типом 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());
}
Натан Перье
источник
Как это не проголосовало больше? Ответ Кунигами неверен (насколько он предполагает основную реализацию).
GreenieMeanie
0

То, что вы запрашиваете, является довольно дорогостоящей операцией, убедитесь, что вам не нужно делать это часто (например, в цикле).

В противном случае вы можете создать собственную коллекцию. Я придумал тот, у которого есть твой TreeBidiMapи TreeMultisetпод капотом. Реализуйте только то, что вам нужно, и заботьтесь о целостности данных.

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.
}

Таким образом, у вас есть отсортированный Multiset вернулся из values(). Однако, если вам нужно, чтобы он был списком (например, вам нужен массивоподобный get(index)метод), вам придется придумывать что-то более сложное.

Vlasec
источник
keySet()и values()являются представлениями к оригиналу Map, поэтому, когда они изменяются, Mapнеобходимо также изменить поддержку, ваше решение не поддерживает это
Lino
0

Java 14 представила, List#copyOfкоторая возвращает неизменяемый список при сохранении порядка:

List<Integer> list = List.copyOf(coll);
Аникет Сахрават
источник
-4

Вот неоптимальное решение в виде однострочника:

Collections.list(Collections.enumeration(coll));
Орхусская
источник