簡體   English   中英

如何在 Rust 中將一串數字轉換為整數數組或向量?

[英]How can I convert a string of numbers to an array or vector of integers in Rust?

我在 STDIN 上寫了一串數字(例如4 10 30 232312 ),我想讀取它並轉換為整數數組(或向量),但我找不到正確的方法。 到目前為止,我有:

use std::io;

fn main() {
    let mut reader = io::stdin();
    let numbers = reader.read_line().unwrap();
}

你可以這樣做:

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);
}

首先,我們鎖定標准輸入,讓您可以將標准輸入用作緩沖讀取器。 默認情況下,Rust 中的 stdin 是無緩沖的; 您需要調用lock()方法來獲取它的緩沖版本,但是這個緩沖版本是程序中所有線程的唯一一個,因此對它的訪問應該是同步的。

接下來,我們閱讀下一行(1); 我正在使用lines()迭代器,其next()方法返回Option<io::Result<String>> ,因此要僅獲取String您需要unwrap()兩次。

然后我們用空格分割它並從額外的空白(2)中修剪結果塊,刪除修剪后留下的空塊(3),將字符串轉換為i32 s(4)並將結果收集到向量(5)。

我們還需要導入std::io::BufRead trait (a) 以使用lines()方法。

如果您事先知道您的輸入不會在數字之間包含多個空格,則可以省略步驟 (3) 並將trim()調用從 (2) 移至 (1):

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

Rust 還提供了一種將字符串拆分為一系列以空格分隔的單詞的方法,稱為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()函數參數來檢查不同種類的空格,而不僅僅是空格字符

在 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().expect("parse error"))
        .collect();

    for num in numbers {
        println!("{}", num);
    }
}

更安全的版本。 這個會跳過失敗的解析,這樣失敗的解包就不會恐慌。 使用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() // split string into words by whitespace
    .filter_map(|w| w.parse().ok()) // calling ok() turns Result to Option so that filter_map can discard None values
    .collect(); // collect items into Vector. This determined by type annotation.

您甚至可以像這樣閱讀 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的閉包。

ok()Result<R,E>Option<R>以便在這種情況下可以過濾錯誤。

Dulguun Otgon更安全版本只是跳過所有錯誤。 如果您不想跳過錯誤,請考慮使用下一種方法。

fn parse_to_vec<'a, T, It>(it: It) -> Result<Vec<T>, <T as FromStr>::Err>
where
    T: FromStr,
    It: Iterator<Item = &'a str>,
{
    it.map(|v| v.parse::<T>()).fold(Ok(Vec::new()), |vals, v| {
        vals.and_then(|mut vals| {
            v.and_then(|v| { 
                vals.push(v);
                Ok(vals)
            })
        })
    })
}    

在使用它時,您可以按照通常的恐慌方式與expect

let numbers = parse_to_vec::<i32, _>(data_str.trim().split(" "))
    .expect("can't parse data");

或更聰明的方式轉換為結果

let numbers = parse_to_vec::<i32, _>(data_str.trim().split(" "))
    .map_err(|e| format!("can't parse data: {:?}", e))?;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM