Подтвердить что ты не робот

Конвертировать запятую строку в список без промежуточного контейнера

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

String numbersArray = "1, 2, 3, 5, 7, 9,";

Есть ли способ конвертировать его сразу в List<Integer>?

Теперь я вижу только один способ сделать это.

List<String> numbers = Arrays.asList(numbersArray.split(","));

И затем

List<Integer> numbersInt = new ArrayList<>();
for (String number : numbers) {
    numbersInt.add(Integer.valueOf(nubmer));
}

Мне любопытно, есть ли способ пропустить часть с List<String> и при первом запуске преобразовать ее в List<Integer>

4b9b3361

Ответ 1

Если вы используете Java 8, вы можете:

int[] numbers = Arrays.asList(numbersArray.split(","))
                      .stream()
                      .map(String::trim)
                      .mapToInt(Integer::parseInt).toArray();

Если нет, я думаю, что ваш подход - лучший вариант.

Ответ 2

Использование java 8 Streams:

List<Integer> longIds = Stream.of(commaSeperatedString.split(","))
                .map(Integer::parseInt)
                .collect(Collectors.toList());

Ответ 3

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

 String numbersArray = "1, 2, 3, 14, 5,";
 List<Integer> list = new ArrayList<Integer>();
 for (int i = 0, j, n = numbersArray.length(); i < n; i = j + 1) {
     j = numbersArray.indexOf(",", i);
     list.add(Integer.parseInt(numbersArray.substring(i, j).trim()));
 }

Однако, это довольно бесполезно, так как на моей машине он примерно в 2 раза медленнее оригинала.

Это следующее решение, с другой стороны, удивительно быстро. Я тестировал его в списках 50000 целых чисел, полученных с помощью Math.abs(random.nextInt()), и он был примерно в 4 раза быстрее оригинала.

List<Integer> list = new ArrayList<Integer>();
for (int i = 0, a = 0, n = numbersArray.length(); i < n; i++) {
    char c = numbersArray.charAt(i);
    if (c == ',') {
        list.add(a);
        a = 0;
    } else if (c != ' ') {
        a = a * 10 + (c - '0');
    }
}

И это примерно в два раза быстрее:

List<Integer> list = new ArrayList<Integer>();
for (int i = 0, a = 0, n = numbersArray.length(); i < n; i++) {
    switch(numbersArray.charAt(i)) {
        case ',': list.add(a); a = 0; break;
        case ' ': break;
        case '0': a = a * 10; break;
        case '1': a = a * 10 + 1; break;
        case '2': a = a * 10 + 2; break;
        case '3': a = a * 10 + 3; break;
        case '4': a = a * 10 + 4; break;
        case '5': a = a * 10 + 5; break;
        case '6': a = a * 10 + 6; break;
        case '7': a = a * 10 + 7; break;
        case '8': a = a * 10 + 8; break;
        case '9': a = a * 10 + 9; break;
        default: throw new AssertionError();
    }
}

Ответ 4

Мне очень нравится ответ @MarounMaroun, но мне интересно, лучше ли использовать Arrays.stream -метод вместо Arrays.asList.

int[] numbers = Arrays.stream(numbersArray.split(","))
                .map(String::trim).mapToInt(Integer::parseInt).toArray();

Этот SO-вопрос обсуждает это далее и суммирует его как таковой:

потому что вы оставляете преобразование массива в поток в JDK - пусть оно отвечает за эффективность и т.д.

Ответ 5

Если вы не используете java8, вы можете использовать Guava

Lists.transform(Arrays.asList(numbersArray.split(",")), new Function<String, Integer>() {
                    @Override
                    public Integer apply(String input) {
                        return Integer.parseInt(input.trim());
                    }
                });

Как упоминал @Maroun для Java8, вы можете использовать потоки.

int[] numbers = Arrays.asList(numbersArray.split(","))
                      .stream()
                      .map(String::trim)
                      .mapToInt(Integer::parseInt).toArray();

Ответ 6

Если вы хотите использовать Google Guava (https://code.google.com/p/guava-libraries/), сплиттер - ваш друг

    List<Integer> list = new ArrayList<Integer>();
    for ( String s : Splitter.on(',').trimResults().omitEmptyStrings().split("1, 2, 3, 14, 5,") ) {
      list.add(Integer.parseInt(s)); 
    }

или вы можете использовать что-то похожее на ваш оригинальный подход и:

List<Integer> list = new ArrayList<Integer>();
for (String s :"1, 2, 3, 5, 7, 9,".split(",") ) {
    list.add(Integer.parseInt(s.trim()));
}

Ответ 7

Я думаю, что ниже фрагмент кода может быть вам полезен.

import java.util.Scanner;

public class Solution {
    public static void main(String[] args) throws java.io.IOException {
        String numbersArray = "1, 2, 3, 5, 7, 9,";
        System.out.println(numbersArray);
        Scanner sc = new Scanner(numbersArray);
        sc.useDelimiter("(, *)*");
        try{
            while(true){
                System.out.println(sc.nextInt());
            }
        } catch (Exception e) {
            System.out.println("reading is completed");
        }
    }
}

Вместо использования System.out.println добавьте его в список Integer.

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