Преобразование Set в List без создания нового списка
Я использую следующий код для преобразования Set
в List
:
Map<String, List<String>> mainMap = new HashMap<>();
for (int i=0; i < something.size(); i++) {
Set<String> set = getSet(...); // возвращает разные результаты каждый раз
List<String> listOfNames = new ArrayList<>(set);
mainMap.put(differentKeyName, listOfNames);
}
Я хочу избежать создания нового списка на каждой итерации цикла. Это возможно?
5 ответ(ов)
Для преобразования Set
в List
с использованием конструктора, вы можете воспользоваться следующим кодом:
Set<?> set = ...; // ваш набор
List<?> list = new ArrayList<>(set);
В этом примере мы создаем новый экземпляр ArrayList
, передавая в его конструктор набор set
. Таким образом, мы успешно преобразуем Set
в List
, используя конструктор ArrayList
. Убедитесь, что типы данных в set
совместимы с вашими требованиями к List
.
Также из библиотеки Guava Collect вы можете использовать newArrayList(Collection)
:
Lists.newArrayList(your_set);
Это будет очень похоже на предыдущий ответ от amit, но вам не нужно декларировать (или создавать) объект list
.
Мы можем использовать следующий однострочник в Java 8:
List<String> list = set.stream().collect(Collectors.toList());
Вот небольшой пример:
public static void main(String[] args) {
Set<String> set = new TreeSet<>();
set.add("A");
set.add("B");
set.add("C");
List<String> list = set.stream().collect(Collectors.toList());
}
Примечание: Такой способ создания списка с использованием стримов имеет накладные расходы по памяти. Если нужно избежать выделения новой памяти, то стоит отказаться от этого решения.
Наиболее простой способ
Я хотел очень быстро преобразовать свой набор в список и вернуть его, поэтому в одну строку я сделал следующее:
return new ArrayList<Long>(mySetVariable);
Для полноты картины...
Предположим, что вы действительно хотите обрабатывать значения Map
как List
, но хотите избежать создания копии Set
в List
каждый раз.
Например, вы можете вызывать одну функцию библиотеки, которая создает Set
, но при этом передаете результат Map<String, List<String>>
в (не очень хорошо спроектированную, но работающую вне вашего контроля) функцию библиотеки, которая принимает только Map<String, List<String>>
. Причем вы как-то точно знаете, что операции, выполняемые с List
, также применимы к любой Collection
(а значит, и к любому Set
). И почему-то вам нужно избежать накладных расходов на скорость и память, вызванных копированием каждого Set
в List
.
В этом очень узком случае, в зависимости от (возможно, неизвестного) поведения функции библиотеки, вам может удастся создать представление List
для каждого Set
. Однако учтите, что это inherently unsafe (поскольку требования функции библиотеки к каждому List
могут измениться, и вы об этом не узнаете), поэтому следует предпочесть другое решение. Но вот как вы могли бы это сделать.
Вы можете создать класс, который реализует интерфейс List
, принимает Set
в конструкторе и присваивает этот Set
полю, а затем использует этот внутренний Set
для реализации API List
(в той мере, в какой это возможно и желательно).
Обратите внимание, что некоторые поведения List
вы просто не сможете воспроизвести без хранения элементов как List
, а некоторые поведения сможете лишь частично. Еще раз, этот класс не является безопасной заменой для List
в общем смысле. В частности, если вы знаете, что в использовании требуются операции, связанные с индексами, или мутация List
, этот подход быстро приведет к проблемам.
public class ListViewOfSet<U> implements List<U> {
private final Set<U> wrappedSet;
public ListViewOfSet(Set<U> setToWrap) { this.wrappedSet = setToWrap; }
@Override public int size() { return this.wrappedSet.size(); }
@Override public boolean isEmpty() { return this.wrappedSet.isEmpty(); }
@Override public boolean contains(Object o) { return this.wrappedSet.contains(o); }
@Override public java.util.Iterator<U> iterator() { return this.wrappedSet.iterator(); }
@Override public Object[] toArray() { return this.wrappedSet.toArray(); }
@Override public <T> T[] toArray(T[] ts) { return this.wrappedSet.toArray(ts); }
@Override public boolean add(U e) { return this.wrappedSet.add(e); }
@Override public boolean remove(Object o) { return this.wrappedSet.remove(o); }
@Override public boolean containsAll(Collection<?> clctn) { return this.wrappedSet.containsAll(clctn); }
@Override public boolean addAll(Collection<? extends U> clctn) { return this.wrappedSet.addAll(clctn); }
@Override public boolean addAll(int i, Collection<? extends U> clctn) { throw new UnsupportedOperationException(); }
@Override public boolean removeAll(Collection<?> clctn) { return this.wrappedSet.removeAll(clctn); }
@Override public boolean retainAll(Collection<?> clctn) { return this.wrappedSet.retainAll(clctn); }
@Override public void clear() { this.wrappedSet.clear(); }
@Override public U get(int i) { throw new UnsupportedOperationException(); }
@Override public U set(int i, U e) { throw new UnsupportedOperationException(); }
@Override public void add(int i, U e) { throw new UnsupportedOperationException(); }
@Override public U remove(int i) { throw new UnsupportedOperationException(); }
@Override public int indexOf(Object o) { throw new UnsupportedOperationException(); }
@Override public int lastIndexOf(Object o) { throw new UnsupportedOperationException(); }
@Override public ListIterator<U> listIterator() { throw new UnsupportedOperationException(); }
@Override public ListIterator<U> listIterator(int i) { throw new UnsupportedOperationException(); }
@Override public List<U> subList(int i, int i1) { throw new UnsupportedOperationException(); }
}
...
Set<String> set = getSet(...);
ListViewOfSet<String> listOfNames = new ListViewOfSet<>(set);
...
Получить различия между двумя списками с уникальными элементами
Самый быстрый способ проверить наличие значения в списке
Как прочитать большой текстовый файл построчно с помощью Java?
Как создать новый список в Java
Почему 2 * (i * i) быстрее, чем 2 * i * i в Java?