schedule2021-03-22

【Rust】数値型のベクトルをスペース区切りの文字列に変換(join)する

Rustの数値型のベクトルをスペースやカンマなどの区切り文字を挟んだ文字列に変換(join)する書き方です。 Rustで競技プログラミングを始めたので必要としました。

vec![1, 2, 3]1 2 3と出力させます。 イメージはPythonのlist.join(" ")

playgroundでコードを実行確認できます。

Contents

構文

// to_string
Vec<T>.iter().map(|x| x.to_string()).collect().join(" ")

// format!
Vec<T>.iter().map(|x| format!("{}", x)).collect().join(",")

この構文でベクトルを区切り文字で結合した文字列へ変換できる。 format!("{}", x)は応用が利くため便利。

以下で例と解説をする。

整数型

整数型のベクトルの例です。

rust
// 整数型
let src: Vec<i32> = vec![-3, -2, -1, 0, 1, 2, 3];

// 要素を整数型から文字列型変換
let dst: Vec<String> = src.iter().map(|x| x.to_string()).collect();
// 文字列型vectorを区切り文字で結合
println!("{}", dst.join(" "));
出力
-3 -2 -1 0 1 2 3

要素が文字列のVec<String>では区切り文字を指定して結合する.join(" ")が利用できます。 そのため、Vec<i32>.map()で要素ごとに文字列へ変換してVec<String>にしています。 区切り文字は.join(",")などと変更できます。

  • iter().map(|x| x.to_string())は要素ごとに文字列へ変換する処理です。Rust版のラムダ式ですかね。
  • .collect()MapVec<T>に直すことができる。

浮動小数点型

浮動小数点型も同じです。

rust
// 浮動小数点型
let src: Vec<f32> = vec![-3.3, -2.2, -1.1, 0.0, 1.1, 2.2, 3.3];

let dst: Vec<String> = src.iter().map(|x| x.to_string()).collect();
println!("{}", dst.join(" "));
出力
-3.3 -2.2 -1.1 0 1.1 2.2 3.3

.0は省略されるようです。

論理値型

浮動小数点型はtrue, falseを出力できます。

// 論理値型
    let src: Vec<bool> = vec![true, false];

    let dst: Vec<String> = src.iter().map(|x| x.to_string()).collect();
    println!("{}", dst.join(" "));
出力
true false

format

format!で要素を文字列にするときのカスタマイズが容易になります。

  • std::fmtに例がたくさんあります。

0埋め, パディング

std::fmt#sign0

// 浮動小数点型 0パディング
let src: Vec<f32> = vec![-3.3, -2.2, -1.1, 0.0, 1.1, 2.2, 3.3];

let dst: Vec<String> = src.iter().map(|x| format!("{:05}", x)).collect();
println!("{}", dst.join(" "));
出力
-03.3 -02.2 -01.1 00000 001.1 002.2 003.3

format!("{:05}", x)が5桁の0埋めです。

その他のサイン。

assert_eq!(format!("Hello {:+}!", 5), "Hello +5!");
assert_eq!(format!("{:#x}!", 27), "0x1b!");
assert_eq!(format!("Hello {:05}!", 5),  "Hello 00005!");
assert_eq!(format!("Hello {:05}!", -5), "Hello -0005!");
assert_eq!(format!("{:#010x}!", 27), "0x0000001b!");

fillalignment

std::fmt#fillalignment

assert_eq!(format!("Hello {:<5}!", "x"),  "Hello x    !");
assert_eq!(format!("Hello {:-<5}!", "x"), "Hello x----!");
assert_eq!(format!("Hello {:^5}!", "x"),  "Hello   x  !");
assert_eq!(format!("Hello {:>5}!", "x"),  "Hello     x!");

文字列型

文字列型の場合は既に要素が文字列であるため、変換が不要です。

let months = vec!["January", "February", "March", "April", "May", "June", "July",
          "August", "September", "October", "November", "December"];
println!("{}", months.join(", "));
出力
January, February, March, April, May, June, July, August, September, October, November, December

タプルの場合

Rustのタプルは異なる型を納められます。 map()はジェネリックだったのと、整数型と浮動小数点型はto_string()を持つため混合していても良いかと考えてましたが、エラーが出ました。

let src = (500, 6.4, 1);
let dst: Vec<String> = src.iter().map(|x| x.to_string()).collect();

println!("{}", dst.join(" "));
出力
error[E0599]: no method named `iter` found for tuple `({integer}, {float}, {integer})` in the current scope
  --&gt; src/main.rs:41:32
   |
41 |     let dst: Vec&lt;String&gt; = src.iter().map(|x| x.to_string()).collect();
   |                                ^^^^ method not found in `({integer}, {float}, {integer})`

error: aborting due to previous error

型を混合したものはiterで扱えないようです。

おわり