Vector や スライスを結合させる方法をまとめてみました!
Vector を結合する
append : Vec + Vec
append は Vec
に Vec
を結合する場合に使用します。
引数に指定した Vec
のすべての要素を呼び出し元の Vec
に追加することができます。
なお、引数に指定した Vec
は空になります。
そのため、どちらも mut
である必要があります。
fn main() {
let mut a = vec![1, 2, 3];
let mut b = vec![4, 5, 6]; // mut が必要
a.append(&mut b);
assert_eq!(a, vec![1, 2, 3, 4, 5, 6]);
assert_eq!(b, vec![]);
}
extend : Vec + Vec
extend は Vec
に Vec
を結合する場合に使用します。
extend
は std::iter::Extend トレイトのメソッドです。
extend
では、引数に指定した Vec
のすべての要素が呼び出し元の Vec
に追加されます。
そして、引数に指定した Vec
の所有権が呼び出し元に移動します。
fn main() {
let mut a = vec![1, 2, 3];
let b = vec![4, 5, 6];
a.extend(b);
assert_eq!(a, vec![1, 2, 3, 4, 5, 6]);
// assert_eq!(b, vec![]); // error[E0382]: borrow of moved value: `b`
}
このエラーを回避するには clone
を渡しましょう。
fn main() {
let mut a = vec![1, 2, 3];
let b = vec![4, 5, 6];
a.extend(b.clone()); // clone する
assert_eq!(a, vec![1, 2, 3, 4, 5, 6]);
assert_eq!(b, vec![4, 5, 6]);
}
extend
の引数には参照を渡すこともできるため、Copy
トレイトを実装している場合は参照を渡すことでもこのエラーを回避できます。
fn main() {
let mut a = vec![1, 2, 3];
let b = vec![4, 5, 6];
a.extend(&b); // 参照を渡す
assert_eq!(a, vec![1, 2, 3, 4, 5, 6]);
assert_eq!(b, vec![4, 5, 6]);
}
また、extend
の引数に iter
を渡すこともできるので、要素を何かしらの処理を加えることができます。
fn main() {
let mut a = vec![1, 2, 3];
let b = vec![4, 5, 6];
// [starting_index..ending_index]
// `starting_index`: スライスの先頭の位置、
// `ending_index`: スライスの末尾の1つ先の位置
a.extend(&b[1..2]);
assert_eq!(a, vec![1, 2, 3, 5]);
assert_eq!(b, vec![4, 5, 6]);
}
fn main() {
let mut a = vec![1, 2, 3];
let b = vec![4, 5, 6];
// map で要素を処理
a.extend(b.iter().map(|x| x + 10));
assert_eq!(a, vec![1, 2, 3, 14, 15, 16]);
assert_eq!(b, vec![4, 5, 6]);
}
extend_from_slice を使う
所有権を移動させたくない場合、参照を渡すことでエラーを回避してきましたが、String
などのコピーできない型が要素の場合は参照を渡すとエラーが発生します。
その際は extend_from_slice を使います。
extend_from_slice
の引数は &[T]
で、Clone
を実装している必要があり、内部でクローンが行われて呼び出し元に追加されます。
fn main() {
let mut a = vec!["a".to_string(), "b".to_string(), "d".to_string()];
let b = vec!["x".to_string(), "y".to_string(), "z".to_string()];
// a.extend(&b);
// error[E0271]: type mismatch resolving `<&Vec<String> as IntoIterator>::Item == String`
a.extend_from_slice(&b); // 参照を渡す
assert_eq!(
a,
vec![
"a".to_string(),
"b".to_string(),
"d".to_string(),
"x".to_string(),
"y".to_string(),
"z".to_string()
]
);
assert_eq!(b, vec!["x".to_string(), "y".to_string(), "z".to_string()]);
}
fn main() {
let mut a = vec!["a".to_string(), "b".to_string(), "d".to_string()];
let b = vec!["x".to_string(), "y".to_string(), "z".to_string()];
a.extend_from_slice(&b[1..2]); // スライスを渡す
assert_eq!(
a,
vec![
"a".to_string(),
"b".to_string(),
"d".to_string(),
"y".to_string()
]
);
assert_eq!(b, vec!["x".to_string(), "y".to_string(), "z".to_string()]);
}
新しい Vector に結合する
iter に変換して chain で結合する
iter
同士を chain で結合することができます。
この場合、結合したい Vec
はイミュータブルのままにすることができます。
fn main() {
let a = vec![1, 2, 3];
let b = vec![4, 5, 6];
// 新しい vec に結合する
let c: Vec<i32> = a.iter().chain(b.iter()).cloned().collect();
assert_eq!(a, vec![1, 2, 3]);
assert_eq!(b, vec![4, 5, 6]);
assert_eq!(c, vec![1, 2, 3, 4, 5, 6]);
}
concat で結合する
concat を使って、複数の Vec
を結合することもできます。
fn main() {
let a = vec![1, 2, 3];
let b = vec![4, 5, 6];
// 新しい vec に結合する
let c: Vec<i32> = [a, b].concat();
assert_eq!(c, vec![1, 2, 3, 4, 5, 6]);
}
Vec
の参照を指定するとエラーになるが、明示的にスライスを指定することができます。
fn main() {
let a = vec![1, 2, 3];
let b = vec![4, 5, 6];
// 新しい vec に結合する
let c: Vec<i32> = [&a[..], &b[..]].concat();
assert_eq!(a, vec![1, 2, 3]);
assert_eq!(b, vec![4, 5, 6]);
assert_eq!(c, vec![1, 2, 3, 4, 5, 6]);
}
starting_index
や ending_index
を指定すれば、配列の一部を結合することもできます。
fn main() {
let a = vec![1, 2, 3];
let b = vec![4, 5, 6];
// [starting_index..ending_index]
// `starting_index`: スライスの先頭の位置、
// `ending_index`: スライスの末尾の1つ先の位置
let c: Vec<i32> = [&a[1..], &b[1..2]].concat();
assert_eq!(a, vec![1, 2, 3]);
assert_eq!(b, vec![4, 5, 6]);
assert_eq!(c, vec![2, 3, 5]);
}
join でセパレータを挿入しながら結合する
join を使えば、セパレータを挿入しながら複数の Vec
を結合することができます。
なお、セパレータには参照を渡す必要があります。
fn main() {
let a = vec![1, 2, 3];
let b = vec![4, 5, 6];
// 新しい vec に結合する
let c: Vec<i32> = [a, b].join(&0);
assert_eq!(c, vec![1, 2, 3, 0, 4, 5, 6]);
}
fn main() {
let a = vec![1, 2, 3];
let b = vec![4, 5, 6];
// [starting_index..ending_index]
// `starting_index`: スライスの先頭の位置、
// `ending_index`: スライスの末尾の1つ先の位置
let c: Vec<i32> = [&a[1..], &b[1..2]].join(&0);
assert_eq!(a, vec![1, 2, 3]);
assert_eq!(b, vec![4, 5, 6]);
assert_eq!(c, vec![2, 3, 0, 5]);
}
まとめ
一口に Vector の結合と言っても、たくさんの方法がありました。
目的に合わせて、使い分けていきましょう!
コメント