Enumチートシートからマップリストの値の操作を学ぶ② - filtering

こんにちは！
プログラミング未経験文系出身、Elixirの国に迷い込んだ？！見習いアルケミストのaliceと申します。
今回はマップリストのデータの操作についてEnumチートシートを写経して学んだことをまとめます。
本記事filtering(絞り込みをする関数群)についてです。

https://hexdocs.pm/elixir/main/enum-cheat.html#filter-enum-fun


# 目的
マップリストの値の操作ができるように様々な関数を知りたい。

## 実行環境
Windows 11 ＋ WSL2 ＋ Ubuntu 22.04
Elixir v1.14.3
Erlang v26.0.2

# 前提
本シリーズは下記でscaffold生成されたPhoenix+LiveViewのプロジェクトを使用しています。
```bash:bash
mix phx.new dec23
cd dec23
mix ecto.create
mix phx.gen.live Users User users name:string age:integer
# 生成されたroutingをrouter.exに記載
mix ecto.migrate
```

# 元データ
```diff_elixir:iex
iex(1)> users = Dec23.Users.list_users
[debug] QUERY OK source="users" db=1.7ms idle=1572.5ms
SELECT u0."id", u0."name", u0."age", u0."inserted_at", u0."updated_at" FROM "users" AS u0 []
↳ :erl_eval.do_apply/7, at: erl_eval.erl:746
[
  %Dec23.Users.User{
    __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
    id: 1,
    name: "santa",
    age: 100,
    inserted_at: ~U[2023-12-23 09:06:44Z],
    updated_at: ~U[2023-12-23 09:06:44Z]
  },
  %Dec23.Users.User{
    __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
    id: 2,
    name: "reindeer",
    age: 55,
    inserted_at: ~U[2023-12-23 09:07:18Z],
    updated_at: ~U[2023-12-23 09:07:18Z]
  },
  %Dec23.Users.User{
    __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
    id: 3,
    name: "dwarf",
    age: 39,
    inserted_at: ~U[2023-12-23 09:07:44Z],
    updated_at: ~U[2023-12-23 09:07:44Z]
  }
]
```


# Enumチートシートとは？
Enumチートシートというものがあります。

https://hexdocs.pm/elixir/main/enum-cheat.html

下記のマップリストを例にしたチートシートです。
幸運なことに元データと同じデータ構造をしています！
```diff_elixir
cart = [
  %{fruit: "apple", count: 3},
  %{fruit: "banana", count: 1},
  %{fruit: "orange", count: 6}
]
```
というわけでこれを写経してみました。

# Enum.filter
第一引数の要素を順番に取り出す。
第二引数の条件に一致する要素だけに絞り込む。

https://hexdocs.pm/elixir/main/Enum.html#filter/2

## お手本の写経[^1]
```diff_elixir:iex
Enum.filter(cart, &(&1.fruit =~ "e"))
[%{count: 6, fruit: "orange"}]
```
```diff_elixir:iex
Enum.filter(cart, &(&1.fruit =~ "an"))
[%{count: 1, fruit: "banana"}, %{count: 6, fruit: "orange"}]
```

## 自分のケースでの演習
```diff_elixir:iex
Enum.filter(users, &(&1.name =~ "a")) #文字列のマッチ演算子を使用した方法
[
  %Dec23.Users.User{
    __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
    id: 1,
    name: "santa",
    age: 100,
    inserted_at: ~U[2023-12-23 09:06:44Z],
    updated_at: ~U[2023-12-23 09:06:44Z]
  },
  %Dec23.Users.User{
    __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
    id: 3,
    name: "dwarf",
    age: 39,
    inserted_at: ~U[2023-12-23 09:07:44Z],
    updated_at: ~U[2023-12-23 09:07:44Z]
  }
]
```
```diff_elixir:iex
users |> Enum.filter(&(&1.name =~ ~r/a/)) #正規表現を使用した方法
[
  %Dec23.Users.User{
    __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
    id: 1,
    name: "santa",
    age: 100,
    inserted_at: ~U[2023-12-23 09:06:44Z],
    updated_at: ~U[2023-12-23 09:06:44Z]
  },
  %Dec23.Users.User{
    __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
    id: 3,
    name: "dwarf",
    age: 39,
    inserted_at: ~U[2023-12-23 09:07:44Z],
    updated_at: ~U[2023-12-23 09:07:44Z]
  }
]
```

# Enum.reject
第一引数の要素を順番に取り出す。
第二引数の条件に一致しない要素だけに絞り込む。

https://hexdocs.pm/elixir/main/Enum.html#reject/2

## お手本の写経
```diff_elixir:iex
Enum.reject(cart, &(&1.fruit =~ "o"))
[%{count: 6, fruit: "orange"}]
```
```diff_elixir:iex
Enum.reject(cart, &(&1.fruit =~ "an"))
[%{count: 3, fruit: "apple"}]
```

## 自分のケースでの演習
```diff_elixir:iex
Enum.reject(users, &(&1.name =~ "a")) #文字列のマッチ演算子を使用した方法
[
  %Dec23.Users.User{
    __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
    id: 2,
    name: "reindeer",
    age: 55,
    inserted_at: ~U[2023-12-23 09:07:18Z],
    updated_at: ~U[2023-12-23 09:07:18Z]
  }
]
```
```diff_elixir:iex
users |> Enum.reject(&(&1.name =~ ~r/a/))  #正規表現を使用した方法
[
  %Dec23.Users.User{
    __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
    id: 2,
    name: "reindeer",
    age: 55,
    inserted_at: ~U[2023-12-23 09:07:18Z],
    updated_at: ~U[2023-12-23 09:07:18Z]
  }
]
```

# 内包表記(for文)[^2]
<- の右側の要素を順番に取り出す。
`do`の前に書かれた条件にヒットした要素にのみ絞り込み、do endブロック内の処理をする。

https://hexdocs.pm/elixir/main/Kernel.SpecialForms.html#for/1

## お手本の写経
```diff_elixir:iex
for item <- cart, item.fruit =~ "e" do
  item
end

[%{count: 3, fruit: "apple"}, %{count: 6, fruit: "orange"}]
```

## 自分のケースでの演習
```diff_elixir:iex
for user <- users, user.name =~ "a" do
 user
end

[
  %Dec23.Users.User{
    __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
    id: 1,
    name: "santa",
    age: 100,
    inserted_at: ~U[2023-12-23 09:06:44Z],
    updated_at: ~U[2023-12-23 09:06:44Z]
  },
  %Dec23.Users.User{
    __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
    id: 3,
    name: "dwarf",
    age: 39,
    inserted_at: ~U[2023-12-23 09:07:44Z],
    updated_at: ~U[2023-12-23 09:07:44Z]
  }
]
```

# 内包表記(for文)とパターンマッチの合わせ技
<- の右側の要素を順番に取り出す。
`do`の前に書かれたパターンマッチにヒットした要素にのみ絞り込み、do endブロック内の処理をする。

## お手本の写経
```diff_elixir:iex
for %{count: 1, fruit: fruit} <- cart do
  fruit
end

["banana"]
```

## 自分のケースでの演習
```diff_elixir:iex
for %Dec23.Users.User{id: id, name: name, age: age} <- users do
  IO.puts("User ID: #{id}, Name: #{name}さんは, Age: #{age}歳です。")
end

User ID: 1, Name: santaさんは, Age: 100歳です。
User ID: 2, Name: reindeerさんは, Age: 55歳です。
User ID: 3, Name: dwarfさんは, Age: 39歳です。
[:ok, :ok, :ok]
```

# ～Elixirの国のご案内～
↓Elixirって何ぞや？と思ったらこちらもどぞ。Elixirは先端のアレコレをだいたい全部できちゃいます:laughing::sparkles::sparkles:

https://qiita.com/piacerex/items/09876caa1e17169ec5e1

↓ゼロからElixirを始めるなら「エリクサーチ」がおすすめ！私もエンジニア未経験から学習中です。

https://elixir-lang.info/topics/entry_column


↓[We Are The Alchemists, my friends!:bouquet:](https://qiita.com/torifukukaiou/items/6bcd5bbb80df9e594e9e "Awesome-san's Awesome article")[^10]
Elixirコミュニティは本当に優しくて温かい人たちばかり！
私が挫折せずにいられるのもこの恵まれた環境のおかげです。
まずは気軽にコミュニティを訪れてみてください。[^11]


https://speakerdeck.com/elijo/elixirkomiyunitei-falsebu-kifang-guo-nei-onrainbian


[^1]: =~ は文字列どうしのマッチ演算子です https://hexdocs.pm/elixir/main/Kernel.html#=~/2

[^2]: 内包表記とは、EnumやStreamを反復するための手法。割とプロダクションで見る機会が多い気がします。早く使い方を覚えたいです。https://elixirschool.com/ja/lessons/basics/comprehensions

[^10]: @torifukukaiouさんのAwesomeな名言をお借りしました。Elixirコミュニティを一言で表すと、これに尽きます。


[^11]: @kn339264さんの素敵なスライドをお借りしました。Elixirコミュニティはいろんな形で活動中！