Як перетворити колекцію в список?


294

Я використовую TreeBidiMapз бібліотеки колекцій Apache . Я хочу сортувати це за значеннями, які є doubles.

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

Collection coll = themap.values();

Що природно працює чудово.

Головне питання: Тепер я хочу знати, як я можу перетворити / передати (не впевнений, що це правильно) collв Listтак, щоб це можна було сортувати?

Тоді я маю намір повторити впорядкований Listоб’єкт, який повинен бути в порядку, і отримати відповідні ключі від TreeBidiMap( themap), використовуючи те, themap.getKey(iterator.next())де ітератор буде над списком doubles.


4
Ви можете уникнути цього кроку, безпосередньо використовуючи якусь сортовану карту, тому записи впорядковані в порядку користування ключами. Власний Java TreeMap реалізує SortedMap.
Аксель Кнауф

TreeBidiMapє OrderedMap, замовлення повинно бути нормальним. Сортування, необхідне у запитанні, здійснюється за значеннями, а не за ключами.
Власек

Відповіді:


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

Як каже Ерел Сегал Халеві нижче, якщо coll вже є списком, ви можете пропустити крок перший. Але це залежало б від внутрішніх даних TreeBidiMap.

List list;
if (coll instanceof List)
  list = (List)coll;
else
  list = new ArrayList(coll);

4
Зауважимо лише, що у двох підходів є різні побічні ефекти: передавання колекції до списку, а потім сортування також сортуватиме оригінальну колекцію; створення копії не буде.
Барні

Цей підхід значно погіршує продуктивність при багаторазовому використанні. Дивіться мою відповідь щодо рішення, яке працює на ходу, воно включає в себе спеціальну колекцію.
Власек

Це не вирішує випадок, коли map.values ​​() повертає колекцію "внутрішнього класу". Компілятор повідомляє, що Collections.sort (Список <T>) не приймає Collections.sort (Список <InnerClass>). Рішення було навіть використовувати: Список <InnerClass> list = map.values ​​(). Stream (). Collection (Collectors.toList ())
Перейра


33

Я думаю, що відповідь Пола Томбліна може бути марною, якщо 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

Чудово! Це вирішило мою справу. My map.values ​​() повертає колекцію "внутрішнього класу". Компілятор повідомив, що Collections.sort (Список <T>) не приймає Collections.sort (Список <InnerClass>).
Перейра

не працював для мого використання в Android. потрібно мінімум api 24
ansh sachdeva

8
Collections.sort( new ArrayList( coll ) );

Відсутня посилання на доступ до ArrayList?
Зак Скривена

@Zach: mmhh хороший момент. Я знав, що є причина для мене, щоб позначити це як CW. BTW Анс Павла - той самий. Я не знаю, чому у нього є лише моє уф.
OscarRyz

4

@Kunigami: Я думаю, ви можете помилитися з приводу newArrayListметоду Гуави . Він не перевіряє, чи є Iterable типом списку, а просто повертає даний список таким, яким він є. Він завжди створює новий список:

@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)метод, схожий на масив ), вам доведеться вигадати щось більш складне.


keySet()і values()це перегляди до оригіналу Map, тож коли вони будуть змінені, підкладку також Mapпотрібно змінити, ваше рішення не підтримує цього
Lino

-4

Ось неоптимальне рішення як однолінійний:

Collections.list(Collections.enumeration(coll));
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.