Преобразование многострочной строки в вектор целых чисел [duplicate]

8
задан David Dias 23 October 2014 в 21:30
поделиться

3 ответа

В Rust 1.5.x рабочим решением является:

fn main() {    
    let mut numbers = String::new();

    io::stdin().read_line(&mut numbers).ok().expect("read error");

    let numbers: Vec<i32> = numbers
        .split_whitespace()
        .map(|s| s.parse().unwrap())
        .collect();

    for num in numbers {
        println!("{}", num);
    }
}
9
ответ дан David Dias 25 August 2018 в 06:03
поделиться

Безопасная версия. Этот пропустить неудачные разборки, так что неудачный разворот не паникует. Используйте read_line для чтения одной строки.

let mut buf = String::new();

// use read_line for reading single line 
std::io::stdin().read_to_string(&mut buf).expect("");

// this one skips failed parses so that failed unwrap doesn't panic
let v: Vec<i32> = buf.split_whitespace().filter_map(|w| w.parse().ok()).collect();

Вы даже можете прочитать Vector of Vectors, как это.

let stdin = io::stdin();
let locked = stdin.lock();
let vv: Vec<Vec<i32>> = locked.lines()
    .filter_map(
        |l| l.ok().map(
            |s| s.split_whitespace()
                 .filter_map(|word| word.parse().ok())
                 .collect()))
    .collect();

Выше один работает для входов, таких как

2 424 -42 124
42 242 23 22 241
24 12 3 232 445

, а затем превращает их в

[[2, 424, -42, 124],
[42, 242, 23, 22, 241],
[24, 12, 3, 232, 445]]

filter_map принимает замыкание, которое возвращает Option<T> и отфильтровывает все None s.

ok() превращает Result<R,E> в Option<R>, чтобы в этом случае можно было отфильтровать ошибки.

1
ответ дан Dulguun Otgon 25 August 2018 в 06:03
поделиться

Обновлено для Rust 1.x

Вы можете сделать что-то вроде этого:

use std::io::{self, BufRead};                   // (a)

fn main() {
    let reader = io::stdin();
    let numbers: Vec<i32> = 
        reader.lock()                           // (0)
              .lines().next().unwrap().unwrap() // (1)
              .split(' ').map(|s| s.trim())     // (2)
              .filter(|s| !s.is_empty())        // (3)
              .map(|s| s.parse().unwrap())      // (4)
              .collect();                       // (5)
    println!("{:?}", numbers);
}

Сначала мы берем блокировку stdin, которая позволяет работать с stdin как (по умолчанию stdin в Rust не загружен, вам нужно вызвать метод lock() для получения буферизованной версии, но эта буферизованная версия является только одной для всех потоков в вашей программе, следовательно, доступ к ней должен быть синхронизированы).

Далее мы читаем следующую строку (1); Я использую lines() -тератор, метод next() возвращает Option<io::Result<String>>, поэтому для получения только String вам нужно unwrap() дважды.

Затем мы разбиваем его на пробелы и обрезаем результирующие куски из дополнительных пробелов (2) удалите пустые куски, оставшиеся после обрезки (3), преобразуйте строки в i32 s (4) и соберите результат с вектором (5).

Нам также понадобятся для импорта std::io::BufRead признака (a) для использования метода lines().

Если вы заранее знаете, что ваш ввод не будет содержать более одного пробела между цифрами, вы можете опустить шаг (3 ) и переместите вызов trim() из (2) в (1):

let numbers: Vec<i32> = 
    reader.lock()
          .lines().next().unwrap().unwrap()
          .trim().split(' ')
          .map(|s| s.parse().unwrap())
          .collect();

Обновить

Однако ржавчина уже предлагает метод разделения строки на последовательность слова split_whitespace() :

let numbers: Vec<i32> =
    reader.read_line().unwrap().as_slice()
        .split_whitespace()
        .map(|s| s.parse().unwrap())
        .collect()

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

13
ответ дан Vladimir Matveev 25 August 2018 в 06:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: