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

503

Я использую этот код для преобразования Setв List:

Map<String, List<String>> mainMap = new HashMap<>();

for (int i=0; i < something.size(); i++) {
  Set<String> set = getSet(...); //returns different result each time
  List<String> listOfNames = new ArrayList<>(set);
  mainMap.put(differentKeyName, listOfNames);
}

Я хочу избежать создания нового списка в каждой итерации цикла. Это возможно?

Мухаммед Имран Тарик
источник
1
Я знаю способ преобразования set в список, как в Q. Я хочу избегать создания нового списка каждый раз в цикле.
Мухаммед Имран Тарик
4
Почему вы не можете просто добавить набор в mainList? Зачем вам нужно конвертировать набор в список?
DagR
1
Вы намерены создать Список <List <? >>
Hiery Nomus
5
Ты не можешь Ваш вопрос воплощает противоречие в терминах.
Маркиз Лорн

Ответы:

803

Вы можете использовать метод List.addAll () . Он принимает коллекцию в качестве аргумента, а ваш набор является коллекцией.

List<String> mainList = new ArrayList<String>();
mainList.addAll(set);

РЕДАКТИРОВАТЬ: как ответить на редактирование вопроса.
Легко видеть, что если вы хотите иметь s Mapсо Listзначениями s, чтобы иметь k разных значений, вам нужно создать k разных списков.
Таким образом: Вы не можете избежать создания этих списков вообще, списки должны быть созданы.

Возможные
обходные пути : Объявите себя Mapкак Map<String,Set>или Map<String,Collection>вместо, и просто вставьте свой набор.

Амит
источник
1
извините, это была главная карта, а не список. см. вопрос
Мухаммед Имран Тарик
@imrantariq: differentKeyNameменяется каждая итерация? Вы действительно хотите something.size()разные возможные значения на ваших картах? Легко видеть, что карта со kсписками в качестве значений должна создавать как минимум kсписки.
Амит
@imrantariq: а вы хотите разные списки для каждого ключа, который я предполагаю?
Амит
@imrantariq: то, что вы запрашиваете, невозможно. Прочитайте мое редактирование для более подробной информации.
Амит
Он вернет NullPointerException в случае, если установлен нуль.
w35l3y
411

Используйте конструктор, чтобы преобразовать его:

List<?> list = new ArrayList<?>(set);
zengsn
источник
21
Он специально сказал, что хочет избежать этого.
mapeters
3
@mook Не имеет значения, так как его требование неосуществимо.
Маркиз Лорн
16
@EJP, тогда его ответ должен сказать, что вместо того, чтобы просто указать что-то, чего ОП не просил без объяснения причин.
mapeters
он избегает этого, этот конструктор использует System.arrayCopy, который делает поверхностные копии, то есть он только копирует ссылки на объекты в массив, который используется для создания списка. Если вы сравните обе коллекции, вы увидите, что они обе содержат ссылки на одни и те же объекты.
Губатрон
На самом деле это не работает на Android. Есть причина почему?
kbluue
84

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

Lists.newArrayList([your_set])

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

chaiyachaiya
источник
1
Если вы используете гуаву, это удобно
vsingh
6
Хотя вы не вызываете конструктор напрямую, этот метод все равно вызывает ArrayListконструктор.
glen3b
Если я не объявляю Список, как я могу использовать созданный Список?
Корай Тугай
@KorayTugay, хорошо, вы извлекаете Lists.newArrayList ([your_set]) в переменную (локальную или глобальную). Например: List <Foo> fooList = Lists.newArrayList (setOfFoo) Но ваш вопрос некорректен. Если вы создаете список, он по крайней мере неявно объявляется (если не явно).
chaiyachaiya
1
Есть предположения, почему это сделал этот метод? Это не кажется лучше, чем new ArrayList<>([your_set]).
DavidS
49

Мы можем использовать следующие один вкладыш в 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());
}
rajadilipkolli
источник
7
Для удобства чтения не рекомендуется. Например, IntelliJ предлагает «new ArrayList <> (set)» и перечисляет более 20 похожих примеров кода, которые можно заменить таким же образом.
rrhrg
точно! @rrhrg, что лучше для производительности, если мы используем set.parallelStream ()?
Гаурав
31

самое простое решение

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

 return new ArrayList<Long>(mySetVariable);
Башир Аль-Момани
источник
1
Это также то, что IntelliJ IDEA предлагает вместо API потоков.
Бен
6

Вы можете использовать это изменение одной строки: Arrays.asList(set.toArray(new Object[set.size()]))

Map<String, List> mainMap = new HashMap<String, List>();

for(int i=0; i<something.size(); i++){
  Set set = getSet(...); 
  mainMap.put(differentKeyName, Arrays.asList(set.toArray(new Object[set.size()])));
}  
Saheed
источник
Исправленный размер, потому что новый Object [0] будет содержать только один элемент, а новый Object [set.size ()] будет содержать все значения
rajadilipkolli
5

Я бы сделал :

Map<String, Collection> mainMap = new HashMap<String, Collection>();

for(int i=0; i<something.size(); i++){
  Set set = getSet(...); //return different result each time
  mainMap.put(differentKeyName,set);
}
Джером Л
источник
5

Поскольку это не было упомянуто до сих пор, в Java 10 вы можете использовать новый copyOfметод фабрики:

List.copyOf(set);

Из Javadoc :

Возвращает неизменяемый Список, содержащий элементы данной Коллекции, в порядке итерации.

beatngu13
источник
3

Java 8 предоставляет возможность использования потоков, и вы можете получить список из Set<String> setString:

List<String> stringList = setString.stream().collect(Collectors.toList());

Хотя внутренняя реализация на данный момент обеспечивает экземпляр ArrayList:

public static <T>
    Collector<T, ?, List<T>> toList() {
        return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
                                   (left, right) -> { left.addAll(right); return left; },
                                   CH_ID);
    }

но JDK не гарантирует это. Как уже упоминалось здесь :

Нет никаких гарантий относительно типа, изменчивости, сериализуемости или безопасности потока возвращаемого списка; если требуется больший контроль над возвращенным списком, используйте toCollection (Supplier).

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

List<String> stringArrayList = setString.stream()
                     .collect(Collectors.toCollection(ArrayList::new));
akhil_mittal
источник
2

Я создаю простой staticметод:

public static <U> List<U> convertSetToList(Set<U> set)
{
    return new ArrayList<U>(set);
}

... или если вы хотите установить тип списка, вы можете использовать:

public static <U, L extends List<U>> List<U> convertSetToList(Set<U> set, Class<L> clazz) throws InstantiationException, IllegalAccessException
{
    L list = clazz.newInstance();
    list.addAll(set);
    return list;
}
thomas.adamjak
источник
2

Недавно я нашел это:

ArrayList<T> yourList = Collections.list(Collections.enumeration(yourSet<T>));
Стенд Ян
источник
1
Можете ли вы расширить или подробнее рассказать об этом?
Вандал
Collections.list () создает новый ArrayList:public static <T> ArrayList<T> list(Enumeration<T> e) { ArrayList<T> l = new ArrayList<>(); while (e.hasMoreElements()) l.add(e.nextElement()); return l; }
Артем Луканин
2

Ради полноты ...

Скажите , что вы действительно хотите , чтобы обработать Mapзначения , как Listс, но вы хотите , чтобы избежать копирования Setв Listкаждый момент времени.

Например, может быть, вы вызываете одну библиотечную функцию, которая создает Set, но вы передаете свой Map<String, List<String>>результат библиотечной функции (плохо спроектированной, но не в ваших руках), которая только выполняет Map<String, List<String>>, хотя каким- то образом вы знаете, что она выполняет операции с Lists одинаково применимы к любому Collection(и, следовательно, к любому Set). И по какой-то причине вам нужно избегать накладных расходов на скорость / память при копировании каждого набора в список.

В этом супер нишевом случае, в зависимости от (возможно, непознаваемого) поведения, необходимого библиотечной функции от вашего List, вы можете создать List представление для каждого набора. Обратите внимание, что это по сути небезопасно (поскольку требования библиотечной функции к каждой из них Listмогут предположительно измениться без вашего ведома), поэтому следует предпочесть другое решение. Но вот как ты это сделаешь.

Вы создали бы класс, который реализует Listинтерфейс, принимает Setконструктор и присваивает это значение Set полю, а затем использует его Setдля реализации ListAPI (насколько это возможно и желательно).

Обратите внимание, что какое-то поведение List вы просто не сможете имитировать, не сохраняя элементы как a List, а какое-то поведение вы сможете имитировать лишь частично. Опять же, этот класс не является безопасной заменой Lists в целом. В частности, если вы знаете, что сценарий использования требует операций, связанных с индексом, или MUTATING 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);
...
Даниэль Эйвери
источник
На самом деле это единственный ответ, который фактически решает поставленную проблему в вопросе!
Лий
Вы можете легко реализовать это, расширив AbstractList
Lii
1

Я нашел это работает нормально и полезно для создания списка из набора.

ArrayList < String > L1 = new ArrayList < String > ();
L1.addAll(ActualMap.keySet());
for (String x: L1) {
    System.out.println(x.toString());
}
Karthic.K
источник
-15
Map<String, List> mainMap = new HashMap<String, List>();

for(int i=0; i<something.size(); i++){
  Set set = getSet(...); //return different result each time
  mainMap.put(differentKeyName, new ArrayList(set));
}
Мухаммед Имран Тарик
источник
11
Вы не избежали создания списка. Этот код тривиально похож на пример в вашем вопросе.
Тейлор
2
Но это не отвечает твоему quezon, не то, что есть ответ.
Маркиз Лорн