Як сортувати набір до списку на Java?


169

У Java у мене є Set, і я хочу перетворити його на відсортовану List. Чи є в java.util.Collectionsупаковці метод, який зробить це для мене?

Відповіді:


214

Відповідь, яку надає ОП , не найкраща. Це неефективно, оскільки створює новий List і непотрібний новий масив. Крім того, він викликає "неперевірені" попередження через проблеми безпеки типу навколо загальних масивів.

Натомість використовуйте щось подібне:

public static
<T extends Comparable<? super T>> List<T> asSortedList(Collection<T> c) {
  List<T> list = new ArrayList<T>(c);
  java.util.Collections.sort(list);
  return list;
}

Ось приклад використання:

Map<Integer, String> map = new HashMap<Integer, String>();
/* Add entries to the map. */
...
/* Now get a sorted list of the *values* in the map. */
Collection<String> unsorted = map.values();
List<String> sorted = Util.asSortedList(unsorted);

3
Дякую! Це SuppressWarnings завжди мене турбувало.
Джеремі Штейн

4
@sunleo UtilКлас - це той, який містить asSortedList()метод, який я написав. Іншими словами, ви пишете Utilклас самостійно і вкладаєте цей код у нього.
erickson

1
ха-ха, я подумав, що це з пакета за замовчуванням, як java.util добре, дякую
sunleo

3
Це може бути приємною загальною функцією Utility, але справа в тому, що вона все ще не є ефективною. Розгляньте сортування на місці, переконайтесь, що ви встановили в потрібному контейнері. Також розгляньте використання TreeSet як прямого контейнера ваших даних. Якщо ваші дані так чи інакше мають бути унікальними, і вам потрібен набір, тоді використовуйте TreeSet, що ловить двох мух за один проміжок.
YoYo

1
Як зауваження людям, які лише читають верхню відповідь: Подивіться на відповідь nschum нижче, де використовуються потоки Java 8. Якщо ви можете використовувати Java 8, перейдіть до цього. вони більш гнучкі та ефективні.
Фелк

74

Сортований набір:

return new TreeSet(setIWantSorted);

або:

return new ArrayList(new TreeSet(setIWantSorted));

Це була моя перша думка, але запитуючий бажав Список
Алекс Б

@ Алекс: Цей підхід все ще можна використовувати; повернути новий ArrayList (новий TreeSet (setIWantSorted))
Jonik

1
Я фактично використовував це рішення, але не радив би цього. Як зазначено в документації на TreeSet (див. Download.oracle.com/javase/1.4.2/docs/api/java/util/… ), він ефективно використовує метод CompareTo () замість методу equals (), тож якщо ви у наборі є два об'єкти, які мають однаковий результат (), вони будуть розглядатися як дублікати і, як такі, не будуть додані до TreeSet. Остерігайся.
fwielstra

24
@fwielstra: Як ви можете мати об'єкти, які є рівними у введенні, оскільки вхід також є a Set?
ryanprayogo

2
@ryanprayogo Варто згадати, як new TreeSetприймає Collections, а не тільки Sets. Далеко не всі, хто читає цю відповідь, будуть використовувати відповіді Set, хоча саме так задається оригінальне запитання.
Кріс

44
List myList = new ArrayList(collection);
Collections.sort(myList);

... все ж слід робити трюк. Додайте аромат за допомогою Generics, де це можливо.


У мене був корисний фрагмент, який я хотів подарувати громаді. Коли я шукав інформацію, я не міг її знайти. Я намагався полегшити роботу наступної людини. stackoverflow.com/questions/18557/…
Джеремі Штейн

1
Так, звичайно, але вказане вами посилання насправді говорить про реальні питання (тобто ті, на які немає відповіді, тоді знайдіть). Ваше запитання тут було лише для того, щоб дати відповідь ... Я міг насправді ввести сотні питань і відповісти собі; це не сенс!
Себ

5
@Seb: Я не згоден. Я не бачу нічого поганого в цьому питанні. Це, очевидно, не було надзвичайно простим питанням, і тепер він знає кращий спосіб, ніж раніше!
Майкл Майерс

3
Це було справжнім питанням, але я знайшов відповідь після того, як Google виявився коротким. Потокового потоку тоді не існувало. Я розмістив його на своєму веб-сайті, і це допомогло комусь іншому, тому я подумав, що це може бути корисним тут.
Джеремі Штейн

Бонус: І якщо вам трапляється сортування власного типу об’єкта, тоді ви завжди можете реалізувати Comparableі переозначити compareToметод.
набстер

42

Ось як це можна зробити за допомогою потоків Java 8:

mySet.stream().sorted().collect(Collectors.toList());

або з користувацьким компаратором:

mySet.stream().sorted(myComparator).collect(Collectors.toList());

9

Завжди безпечно використовувати компаратор або порівняльний інтерфейс для забезпечення реалізації сортування (якщо об'єкт не є класами String або Wrapper для примітивних типів даних). Як приклад реалізації компаратора для сортування працівників на основі імені

    List<Employees> empList = new LinkedList<Employees>(EmpSet);

    class EmployeeComparator implements Comparator<Employee> {

            public int compare(Employee e1, Employee e2) {
                return e1.getName().compareTo(e2.getName());
            }

        }

   Collections.sort(empList , new EmployeeComparator ());

Компаратор корисний, коли вам потрібно мати різні алгоритми сортування на одному об’єкті (скажіть ім'я співпраці, заробітну плату тощо). Сортування в режимі одиночного режиму може бути здійснено за допомогою порівняльного інтерфейсу до потрібного об'єкта.


5

Не існує єдиного методу для цього. Використовуй це:

@SuppressWarnings("unchecked")
public static <T extends Comparable> List<T> asSortedList(Collection<T> collection) {
  T[] array = collection.toArray(
    (T[])new Comparable[collection.size()]);
  Arrays.sort(array);
  return Arrays.asList(array);
}

Існує також функція Collections.sort, але я думаю, вона робить те саме. +1 у будь-якому випадку.
CookieOfFortune

1
Collections.sort приймає список як параметр.
Джеремі Штейн

3

Ви можете перетворити набір у ArrayList, де можна сортувати ArrayListвикористання Collections.sort(List).

Ось код:

keySet = (Set) map.keySet();
ArrayList list = new ArrayList(keySet);     
Collections.sort(list);

3
TreeSet sortedset = new TreeSet();
sortedset.addAll(originalset);

list.addAll(sortedset);

де originalset = несортований набір та list = список, який потрібно повернути


TreeSet також видаляє список, який може призвести до неправильного результату, якщо ви цього не вважаєте.
anthonymonori

2

@Jeremy Stein Я хотів реалізувати той самий код. Так само я хотів сортувати набір за списком, тож замість того, щоб використовувати Set, я перетворив задані значення у List та сортував цей список за однією змінною. Цей код мені допоміг,

set.stream().sorted(Comparator.comparing(ModelClassName::sortingVariableName)).collect(Collectors.toList());

0

Я використовую цей код, який вважаю більш практичним, ніж прийнята відповідь вище:

List<Thing> thingList = new ArrayList<>(thingSet);
thingList.sort((thing1, thing2) -> thing1.getName().compareToIgnoreCase(thing2.getName()));
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.