1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Rustで配列内の特定の値のみ処理する様々な方法

Last updated at Posted at 2025-05-16

ここでは様々な方法を駆使して配列内の特定の値を処理する様々な方法が書かれています。

ここではfilterメソッドとfindメソッドを使ったやり方で、
特定の値を抽出する方法について説明していきます。

findメソッドを使用したやり方は、趣味でRustのBevyでゲーム開発をしている中で見つけたもので、
filterメソッドはこの記事を公開した時に記事を見てくれた方から教えてもらったものです。

それぞれのメソッドの書き方や、違いなども説明していきますのでよろしくお願いします。

まずはデータを定義

まずは検証を行うためのデータを定義します。

今回は人のデータPerson構造体と、性別のタイプGender列挙型を定義していきます。

deriveには比較するためのPartialEq、コンソールに出力するためのDebugを追加します。

あとは値をわかりやすく定義するためにnewメソッドを追加しています。

newメソッドを追加することで、Person::new(name, age, gender)の形式で
値を定義することができるようになります。

#[derive(PartialEq, Debug)]
struct Person {
    name: String,
    age: usize,
    gender: Gender,
}

#[derive(PartialEq, Debug)]
enum Gender {
    Male,
    Female,
}

impl Person {
    fn new(name: &str, age: usize, gender: Gender) -> Self {
        let name = name.to_string();
        Person {
            name,
            age,
            gender,
        }
    }
}

次にmain関数内で値を定義していきましょう!
以下のコードでは複数のPersonを定義し、その値を配列の変数に入れてまとめています。

fn main() {
    // まずはデータを定義
    let john = Person::new("John", 20, Gender::Male);
    let marry = Person::new("Marry", 21, Gender::Female);
    let bob = Person::new("Bob", 18, Gender::Male);
    let carol = Person::new("Carol", 24, Gender::Female);
    let person_list = [john, marry, bob, carol];
}

これで準備はできました!次は実践していきます!

for文を使った処理

説明の前にfor文での処理を紹介します。
悪い例ではないのですが、これから紹介する実装方法に比べて、少し分かりにくいものになっています。

以下のコードでは配列をfor文でループして一番上に「条件に合わない値を飛ばす」処理を追加して
「条件に合った値を出力する」処理が書かれています。

このコードでも動作はします。「値をループさせて特定の値でなければ飛ばして、特定の値なら出力する」
みたいにパッと見て処理の内容がわかって分かりやすいのですが、条件式が分かりづらく感じます。

fn main() {
    // ...
    forloop(&person_list);
}

fn forloop(person_list: &[Person; 4]) {
    for (index, person) in person_list.iter().enumerate() {
        if person.gender != Gender::Male {
            continue;
        }
        println!("index: {}", index);
        println!("person: {:?}", person);
    }
}

filterメソッドを使った処理

ではfilterメソッドを使用した処理を見ていきましょう。
このコードは上記のコードと同じ結果になります。

ここではPersonのデータが入った配列の変数をループさせ、
filterメソッドで条件に合った値のみを抽出し、その値のみを処理するといった流れになります。

以下のコードはfor文の例よりも、見やすく分かりやすいように見えます。
特に条件文がわかりやすくなったことで「どのような値を抽出するのか」が
パッと見てわかるようになったと思います。

fn main() {
    // ...
    loopfilter(&person_list);
}

fn loopfilter(person_list: &[Person; 4]) {
    person_list
        .iter()
        .enumerate()
        .filter(|(_index, person)| person.gender == Gender::Male)
        .for_each(|(index, person)| {
            println!("index: {}", index);
            println!("person: {:?}", person);
        });
}

findメソッドを使った処理

次にfindメソッドを使用した処理を見ていきましょう。
このコードは上記のコードと少し異なる結果になります。

ここではPersonのデータが入った配列の変数をループさせ、
findメソッドを使って値を取り出し、その値をSome((index, person))に代入します。
そして代入された値はfindメソッド下の鉤括弧の中で処理されます。

結果が少し異なるといった点は、findメソッドで条件に合った最初の値のみ処理が実行される点です。
つまりループをしてfindメソッドで条件に合った値が見つかった場合、
それ以降にループされる値がもしも条件に合っていても処理が実行されず無視されます。

つまり最初の値のみ処理されると言うことはSome((index, person))に代入される値は1つと言うことになります。

findメソッドのメリットとしてはループされる値の中で、
条件に合った1つだけの値を取得したい時などに良いです。

fn main() {
    // ...
    ifletfind(&person_list);
}

fn ifletfind(person_list: &[Person; 4]) {
    if let Some((index, person)) = person_list
        .iter()
        .enumerate()
        .find(|(_, person_value)| person_value.gender == Gender::Male)
    {
        println!("index: {}", index);
        println!("person: {:?}", person);
    }
}

if letとは

findメソッドの使用例にif letを使いましたのでここで簡単な説明をしています。

if letの説明は「Rust By Example 日本語版」で見ることができます。

公式が言うには、match式を使うほど大掛かりな処理ではなく、
小さな処理を書く時にmatch式だと不自然な書き方になってしまう。

その際にif letを使うと綺麗に書くことができるよと書かれています。

つまり、以下のコードのようにnumberが1だったら鉤括弧の中の処理を実行するよと言うことです。
もしもnumberが1以外だったら処理は実行されないと言うことですね。
numberが1以外の時の何か処理を書いておきたいときも、元はif文なのでelseを使うこともできるみたいです。

let number = 1;

if let 1 = number {
    println!("number is 1");
} else {
    println!("number is not 1");
}

コード全容

今回作成したRustのコードは以下のようになります。

#[derive(PartialEq, Debug)]
struct Person {
    name: String,
    age: usize,
    gender: Gender,
}

#[derive(PartialEq, Debug)]
enum Gender {
    Male,
    Female,
}

impl Person {
    fn new(name: &str, age: usize, gender: Gender) -> Self {
        let name = name.to_string();
        Person {
            name,
            age,
            gender,
        }
    }
}

fn main() {
    // まずはデータを定義
    let john = Person::new("John", 20, Gender::Male);
    let marry = Person::new("Marry", 21, Gender::Female);
    let bob = Person::new("Bob", 18, Gender::Male);
    let carol = Person::new("Carol", 24, Gender::Female);
    let person_list = [john, marry, bob, carol];

    forloop(&person_list);
    loopfilter(&person_list);
    ifletfind(&person_list);
}

fn forloop(person_list: &[Person; 4]) {
    for (index, person) in person_list.iter().enumerate() {
        if person.gender != Gender::Male {
            continue;
        }
        println!("index: {}", index);
        println!("person: {:?}", person);
    }
}

fn loopfilter(person_list: &[Person; 4]) {
    person_list
        .iter()
        .enumerate()
        .filter(|(_index, person)| person.gender == Gender::Male)
        .for_each(|(index, person)| {
            println!("index: {}", index);
            println!("person: {:?}", person);
        });
}

fn ifletfind(person_list: &[Person; 4]) {
    if let Some((index, person)) = person_list
        .iter()
        .enumerate()
        .find(|(_, person_value)| person_value.gender == Gender::Male)
    {
        println!("index: {}", index);
        println!("person: {:?}", person);
    }
}

結果は以下のようになります。

$ cargo run
#
# index: 0
# person: Person { name: "John", age: 20, gender: Male }
# index: 2
# person: Person { name: "Bob", age: 18, gender: Male }
# index: 0
# person: Person { name: "John", age: 20, gender: Male }
# index: 2
# person: Person { name: "Bob", age: 18, gender: Male }
# index: 0
# person: Person { name: "John", age: 20, gender: Male }

まとめ

今回は配列内の特定の値のみ処理する様々な方法について説明してみました。

findメソッドを使用した例でif letの使い方が分からずその使用を避けていましたが、
ゲーム開発時に使える場面が出てきてこれは使えるぞ!と感動しました。
この感動をバネにこの記事を書いたわけですが、本当に便利な機能だと思います。

filterメソッドは記事のコメントで教えてもらった事で、このコードも使えるぞ!と言うことで
記事にfilterメソッドの実装方法を追加して更新しました。

もしこの記事が何かの参考になれたら幸いです。
ここまで読んでいただきありがとうございました!

1
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?