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()
はMap
をVec<T>
に直すことができる。- std::iter.collect
std::iter::Map
はstd::iter
を継承しているっぽい。
浮動小数点型
浮動小数点型も同じです。
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埋め, パディング
// 浮動小数点型 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
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
--> src/main.rs:41:32
|
41 | let dst: Vec<String> = src.iter().map(|x| x.to_string()).collect();
| ^^^^ method not found in `({integer}, {float}, {integer})`
error: aborting due to previous error
型を混合したものはiter
で扱えないようです。
おわり
【Rust】エラーが出たときの RUST_BACKTRACE=1 を設定する
Rustschedule2021-04-20
Rustのnumクレートの実行サンプル
Rustschedule2021-04-19