Преобразование List‹Integer› в List‹String›

У меня есть список целых чисел, List<Integer>, и я хотел бы преобразовать все целые объекты в строки, таким образом закончив с новым List<String>.

Естественно, я мог бы создать новый List<String> и пройтись по списку, вызывая String.valueOf() для каждого целого числа, но мне было интересно, есть ли лучший (читай: более автоматический) способ сделать это?


person ChrisThomas123    schedule 20.08.2008    source источник


Ответы (22)


Насколько я знаю, итерация и создание экземпляров - единственный способ сделать это. Что-то вроде (для потенциальной помощи другим, так как я уверен, что вы знаете, как это сделать):

List<Integer> oldList = ...
/* Specify the size of the list up front to prevent resizing. */
List<String> newList = new ArrayList<>(oldList.size());
for (Integer myInt : oldList) { 
  newList.add(String.valueOf(myInt)); 
}
person jsight    schedule 20.08.2008
comment
Когда это просто, это называется красота. - person Elbek; 07.09.2012
comment
Первоначальный плакат, казалось, указывал на то, что он думал об этом, но посчитал это решение слишком сложным или утомительным. Но мне трудно представить, что может быть проще. Да, иногда вам нужно написать 3 или 4 строки кода, чтобы выполнить работу. - person Jay; 07.09.2012
comment
Но это привязывает вас к ArrayList. Можно ли это сделать, используя ту же реализацию, что и исходный список? - person alianos-; 10.04.2013
comment
@Andreas oldList.getClass().newInstance() подойдет - person Lluis Martinez; 09.05.2013
comment
Красиво и чисто. - person Adnan; 01.10.2020

Используя Коллекции Google от Guava-Project, вы можете использовать метод transform в класс Lists

import com.google.common.collect.Lists;
import com.google.common.base.Functions

List<Integer> integers = Arrays.asList(1, 2, 3, 4);

List<String> strings = Lists.transform(integers, Functions.toStringFunction());

List, возвращаемый transform, представляет собой представление в резервном списке — преобразование будет применяться при каждом доступе к преобразованному списку.

Имейте в виду, что Functions.toStringFunction() выдаст NullPointerException при применении к null, поэтому используйте его только в том случае, если вы уверены, что ваш список не будет содержать null.

person Ben Lings    schedule 04.08.2009
comment
Было бы неплохо, если бы помимо Functions.toStringFunction() было больше готовых функций. - person ThiamTeck; 07.09.2010
comment
чисто, но, возможно, не так быстро. 1 дополнительный вызов функции на значение? - person h3xStream; 09.12.2010
comment
HotSpot может встраивать вызовы функций, поэтому, если он вызывается достаточно, это не должно иметь значения. - person Ben Lings; 09.12.2010
comment
Я не минусую это, потому что это действительно решение. Но поощрять людей добавлять зависимость от библиотеки для решения такой простой задачи для меня недопустимо. - person estani; 28.02.2014
comment
Хорошее решение, если вы уже используете Guava в нашем решении. - person dudinha-dedalus; 28.04.2015
comment
Потенциальная проблема заключается в том, что преобразование применяется лениво (возможно, много раз). Вместо этого вы можете вернуть new ArrayList<>(Lists.transform(integers, Functions.toStringFunction())), чтобы избежать этого, - person JRA_TLL; 06.01.2016
comment
Обратное, если вы наткнулись на этот вопрос в поисках String -> Number: Lists.transform(listOfStrings, Ints.stringConverter()); - person LateralFractal; 18.02.2016

Решение для Java 8. Немного дольше, чем решение для Guava, но, по крайней мере, вам не нужно устанавливать библиотеку.

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

//...

List<Integer> integers = Arrays.asList(1, 2, 3, 4);
List<String> strings = integers.stream().map(Object::toString)
                                        .collect(Collectors.toList());
person Trejkaz    schedule 11.04.2014
comment
Хотя это немного длиннее для примера toString, оно оказывается короче для преобразований, не поддерживаемых библиотекой функций Guava. Пользовательские функции по-прежнему просты, но это значительно больше кода, чем этот поток Java 8. - person lightswitch05; 24.10.2017
comment
Вот и обратный путь, для будущих читателей. Спасибо Трейказ! Коллекция‹String› keys = бла-бла-бла; Коллекция‹Целое› keyInts = keys.stream().map(Integer::parseInt).collect(Collectors.toList()); - person granadaCoder; 17.10.2020

То, что вы делаете, прекрасно, но если вы чувствуете потребность в «Java-it-up», вы можете использовать Transformer и метод сбора из Apache Commons, например:

public class IntegerToStringTransformer implements Transformer<Integer, String> {
   public String transform(final Integer i) {
      return (i == null ? null : i.toString());
   }
}

..а потом..

CollectionUtils.collect(
   collectionOfIntegers, 
   new IntegerToStringTransformer(), 
   newCollectionOfStrings);
person SCdF    schedule 21.08.2008
comment
CollectionUtils.collect(коллекцияцелых, новый org.apache.commons.collections.functors.StringValueTransformer()); Но StringValueTransformer использует String.valueOf... - person Kannan Ekanath; 17.02.2010
comment
Если над коллекциями Apache не была проделана новая работа, они не делают дженерики. - person KitsuneYMG; 07.03.2010
comment
Это действительно Java-это вниз. Это не идиоматическая Java, а скорее функциональное программирование. Может быть, когда мы получим замыкания в Java 8, вы могли бы назвать это идиоматической Java. - person Christoffer Hammarström; 08.01.2012
comment
Вы определенно хотите использовать для этого Collections4 (а не старые 3.x Collections) для поддержки дженериков: commons.apache.org/proper/commons-collections/apidocs/org / - person JRA_TLL; 06.01.2016
comment
Определение нового класса только для того, чтобы быть более ООП или идиоматичным... Я не вижу, чем это лучше, чем простой цикл for-each. Это требует больше кода и отодвигает функциональность (что можно смягчить с помощью анонимных классов, но все же). Этот функциональный стиль начинает приносить пользу только при наличии достойного синтаксиса (т. е. лямбда-выражений начиная с Java 8), который функциональные языки обеспечивали десятилетиями. - person TheOperator; 01.02.2016

Источник для String.valueOf показывает это:

public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}

Не то чтобы это имело большое значение, но я бы использовал toString.

person Mike Polen    schedule 20.08.2008

Вместо использования String.valueOf я бы использовал .toString(); он избегает некоторых автобоксов, описанных @johnathan.holland

В javadoc сказано, что valueOf возвращает то же самое, что и Integer.toString().

List<Integer> oldList = ...
List<String> newList = new ArrayList<String>(oldList.size());

for (Integer myInt : oldList) { 
  newList.add(myInt.toString()); 
}
person ScArcher2    schedule 20.08.2008
comment
как указал Том Хотин в «выигрышном» ответе, нельзя создать экземпляр List‹String›, поскольку это всего лишь интерфейс. - person Stu Thompson; 15.09.2008
comment
Хех я знал это. Просто я написал код, не попробовав его. Я исправлю это в своем ответе. - person ScArcher2; 15.09.2008

Вот однострочное решение без обмана с библиотекой, отличной от JDK.

List<String> strings = Arrays.asList(list.toString().replaceAll("\\[(.*)\\]", "$1").split(", "));
person Garrett Hall    schedule 25.04.2011

Другое решение с использованием Guava и Java 8

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<String> strings = Lists.transform(numbers, number -> String.valueOf(number));
person sandrozbinden    schedule 25.04.2014

Не основная Java и не обобщенная, но в популярной библиотеке коллекций Jakarta Commons есть несколько полезных абстракций для такого рода задач. В частности, взгляните на методы сбора на

CollectionUtils

Кое-что, что следует учитывать, если вы уже используете коллекции Commons в своем проекте.

person serg10    schedule 20.08.2008
comment
Никогда не используйте коллекции Apache. Они старые, устаревшие, не безопасные для типов и плохо написанные. - person KitsuneYMG; 07.03.2010

Людям, обеспокоенным «боксом» в jsight, ответ: его нет. Здесь используется String.valueOf(Object), и распаковка в int никогда не выполняется.

Используете ли вы Integer.toString() или String.valueOf(Object), зависит от того, как вы хотите обрабатывать возможные значения NULL. Вы хотите создать исключение (возможно) или иметь «нулевые» строки в своем списке (возможно). Если первое, вы хотите выбросить NullPointerException или какой-то другой тип?

Кроме того, один небольшой недостаток в ответе jsight: List — это интерфейс, вы не можете использовать новый оператор на нем. Я бы, вероятно, использовал java.util.ArrayList в этом случае, тем более что мы заранее знаем, насколько длинным будет список.

person erickson    schedule 28.08.2008

Немного более лаконичное решение с использованием метода forEach в исходном списке:

    List<Integer> oldList = Arrays.asList(1, 2, 3, 4, 5);
    List<String> newList = new ArrayList<>(oldList.size());
    oldList.forEach(e -> newList.add(String.valueOf(e)));
person Solubris    schedule 15.04.2020

@Jonathan: я могу ошибаться, но я считаю, что String.valueOf() в этом случае вызовет функцию String.valueOf(Object), а не будет упакована в String.valueOf(int). String.valueOf(Object) просто возвращает "null", если оно равно null, или вызывает Object.toString(), если оно не равно null, что не должно включать бокс (хотя, очевидно, задействовано создание экземпляров новых строковых объектов).

person jsight    schedule 20.08.2008

Я думаю, что использование Object.toString() для любых целей, кроме отладки, вероятно, действительно плохая идея, хотя в этом случае они функционально эквивалентны (при условии, что в списке нет нулей). Разработчики могут без предупреждения изменять поведение любого метода toString(), включая методы toString() любых классов стандартной библиотеки.

Даже не беспокойтесь о проблемах с производительностью, вызванных процессом упаковки/распаковки. Если производительность критична, просто используйте массив. Если это действительно критично, не используйте Java. Попытка перехитрить JVM приведет только к сердечной боли.

person Outlaw Programmer    schedule 20.08.2008

Ответ только для экспертов:

    List<Integer> ints = ...;
    String all = new ArrayList<Integer>(ints).toString();
    String[] split = all.substring(1, all.length()-1).split(", ");
    List<String> strs = Arrays.asList(split);
person Tom Hawtin - tackline    schedule 11.09.2008
comment
Это работает, но за счет неэффективности. Строки Java представляют собой два байта на символ, поэтому , добавляет четыре байта фиксированной стоимости за целое число перед подсчетом самого целого числа.... среди прочего. - person Robert Christian; 14.10.2010
comment
Я думаю, что регулярное выражение может быть проблемой с точки зрения эффективности цикла процессора. С точки зрения памяти, я полагаю, что разумная реализация (при условии, что Sun неразумна реализация String) будет использовать один и тот же резервный массив (из all), поэтому на самом деле будет очень эффективно использовать память, что было бы важно для долгосрочной производительности. Если вы, конечно, не хотите сохранить только один из элементов... - person Tom Hawtin - tackline; 14.10.2010

Lambdaj позволяет сделать это очень простым и удобочитаемым способом. Например, предположим, что у вас есть список целых чисел, и вы хотите преобразовать их в соответствующее строковое представление, вы можете написать что-то вроде этого;

List<Integer> ints = asList(1, 2, 3, 4);
Iterator<String> stringIterator = convertIterator(ints, new Converter<Integer, String> {
    public String convert(Integer i) { return Integer.toString(i); }
}

Lambdaj применяет функцию преобразования только во время повторения результата.

person Mario Fusco    schedule 07.03.2010

Вы не можете избежать «накладных расходов на бокс»; Поддельные универсальные контейнеры Java могут хранить только объекты, поэтому ваши целые числа должны быть упакованы в целые числа. В принципе, можно было бы избежать преобразования Object в Integer (поскольку это бессмысленно, потому что Object достаточно хорош как для String.valueOf, так и для Object.toString), но я не знаю, достаточно ли умен компилятор для этого. Преобразование из строки в объект должно быть более или менее бесперспективным, поэтому я бы не стал беспокоиться об этом.

person DrPizza    schedule 20.08.2008
comment
компилятор НЕ достаточно умен, чтобы сделать это. Когда javac запускается, он фактически удаляет всю информацию о типе дженериков. Базовая реализация коллекции дженериков ВСЕГДА хранит ссылки на объекты. На самом деле вы можете опустить параметризацию ‹T› и получить необработанный тип. Список l = новый список() по сравнению со списком‹String› l = новый список‹String›(). конечно, это означает, что List‹String› l = (List‹String›)new List‹Integer›() действительно скомпилируется и запустится, но это, очевидно, очень опасно. - person Dave Dopson; 05.06.2011

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

It will be really good to remove the integer from the List<Integer> and free
the space, once it's added to List<String>.

Мы можем использовать итератор для достижения того же самого.

    List<Integer> oldList = new ArrayList<>();
    oldList.add(12);
    oldList.add(14);
    .......
    .......

    List<String> newList = new ArrayList<String>(oldList.size());
    Iterator<Integer> itr = oldList.iterator();
    while(itr.hasNext()){
        newList.add(itr.next().toString());
        itr.remove();
    }
person nagendra547    schedule 29.08.2017

Использование потоков: если, скажем, результатом является список целых чисел (List<Integer> result), то:

List<String> ids = (List<String>) result.stream().map(intNumber -> Integer.toString(intNumber)).collect(Collectors.toList());

Один из способов ее решения. Надеюсь это поможет.

person Shirish Singh    schedule 03.10.2019

Просто для удовольствия, решение, использующее инфраструктуру fork-join jsr166y, которая должна быть в JDK7.

import java.util.concurrent.forkjoin.*;

private final ForkJoinExecutor executor = new ForkJoinPool();
...
List<Integer> ints = ...;
List<String> strs =
    ParallelArray.create(ints.size(), Integer.class, executor)
    .withMapping(new Ops.Op<Integer,String>() { public String op(Integer i) {
        return String.valueOf(i);
    }})
    .all()
    .asList();

(Отказ от ответственности: не скомпилировано. Спецификация не завершена. И т. д.)

Маловероятно, что в JDK7 есть немного вывода типа и синтаксического сахара, чтобы сделать вызов withMapping менее подробным:

    .withMapping(#(Integer i) String.valueOf(i))
person Tom Hawtin - tackline    schedule 14.09.2008

Это такая простая вещь, что я бы не стал использовать внешнюю библиотеку (это вызовет зависимость в вашем проекте, которая вам, вероятно, не нужна).

У нас есть класс статических методов, специально созданных для таких задач. Поскольку код для этого очень прост, мы позволили Hotspot сделать оптимизацию за нас. Кажется, это тема моего кода в последнее время: писать очень простой (прямой) код и позволить Hotspot делать свое волшебство. У нас редко возникают проблемы с производительностью, связанные с таким кодом — когда появляется новая версия виртуальной машины, вы получаете все дополнительные преимущества в скорости и т. д.

Как бы я ни любил коллекции Jakarta, они не поддерживают Generics и используют 1.4 в качестве ЖК-дисплея. Я настороженно отношусь к коллекциям Google, потому что они указаны как уровень поддержки Alpha!

person Community    schedule 24.09.2008

Я просто хотел присоединиться к объектно-ориентированному решению проблемы.

Если вы моделируете объекты домена, то решение находится в объектах домена. Домен здесь представляет собой список целых чисел, для которых нам нужны строковые значения.

Самый простой способ — вообще не преобразовывать список.

При этом, чтобы преобразовать без преобразования, измените исходный список Integer на List of Value, где Value выглядит примерно так...

class Value {
    Integer value;
    public Integer getInt()
    {
       return value;
    }
    public String getString()
    {
       return String.valueOf(value);
    }
}

Это будет быстрее и займет меньше памяти, чем копирование списка.

Удачи!

person Rodney P. Barbati    schedule 07.09.2012

person    schedule
comment
@RequiresApi(api = Build.VERSION_CODES.N) - person Adnan; 01.10.2020