6

Преобразование Set в List без создания нового списка

1

Я использую следующий код для преобразования 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 ответ(ов)

5

Для преобразования Set в List с использованием конструктора, вы можете воспользоваться следующим кодом:

Set<?> set = ...; // ваш набор
List<?> list = new ArrayList<>(set);

В этом примере мы создаем новый экземпляр ArrayList, передавая в его конструктор набор set. Таким образом, мы успешно преобразуем Set в List, используя конструктор ArrayList. Убедитесь, что типы данных в set совместимы с вашими требованиями к List.

0

Также из библиотеки Guava Collect вы можете использовать newArrayList(Collection):

Lists.newArrayList(your_set);

Это будет очень похоже на предыдущий ответ от amit, но вам не нужно декларировать (или создавать) объект list.

0

Мы можем использовать следующий однострочник в 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());
}

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

0

Наиболее простой способ

Я хотел очень быстро преобразовать свой набор в список и вернуть его, поэтому в одну строку я сделал следующее:

return new ArrayList<Long>(mySetVariable);
0

Для полноты картины...

Предположим, что вы действительно хотите обрабатывать значения 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);
...
Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь