日本の山岳一覧・百名山 API を開発しましたCLICK !

Rust | Vector を append や extend で結合する

Rust vec.append vec.extend
  • URLをコピーしました!

Vector や スライスを結合させる方法をまとめてみました!

目次

Vector を結合する

append : Vec + Vec

appendVecVec を結合する場合に使用します。

引数に指定した 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

extendVecVec を結合する場合に使用します。

extendstd::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_indexending_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 の結合と言っても、たくさんの方法がありました。

目的に合わせて、使い分けていきましょう!

Rust vec.append vec.extend

この記事が気に入ったら
フォローしてね!

  • URLをコピーしました!

コメント

コメントする

目次