LoginSignup
8
0

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

Last updated at Posted at 2023-12-23

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

目的

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

実行環境

Windows 11 + WSL2 + Ubuntu 22.04
Elixir v1.14.3
Erlang v26.0.2

前提

本シリーズは下記でscaffold生成されたPhoenix+LiveViewのプロジェクトを使用しています。

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

元データ

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チートシートというものがあります。

下記のマップリストを例にしたチートシートです。
幸運なことに元データと同じデータ構造をしています!

cart = [
  %{fruit: "apple", count: 3},
  %{fruit: "banana", count: 1},
  %{fruit: "orange", count: 6}
]

というわけでこれを写経してみました。

Enum.filter

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

お手本の写経1

iex
Enum.filter(cart, &(&1.fruit =~ "e"))
[%{count: 6, fruit: "orange"}]
iex
Enum.filter(cart, &(&1.fruit =~ "an"))
[%{count: 1, fruit: "banana"}, %{count: 6, fruit: "orange"}]

自分のケースでの演習

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]
  }
]
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

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

お手本の写経

iex
Enum.reject(cart, &(&1.fruit =~ "o"))
[%{count: 6, fruit: "orange"}]
iex
Enum.reject(cart, &(&1.fruit =~ "an"))
[%{count: 3, fruit: "apple"}]

自分のケースでの演習

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]
  }
]
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ブロック内の処理をする。

お手本の写経

iex
for item <- cart, item.fruit =~ "e" do
  item
end

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

自分のケースでの演習

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ブロック内の処理をする。

お手本の写経

iex
for %{count: 1, fruit: fruit} <- cart do
  fruit
end

["banana"]

自分のケースでの演習

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:

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

We Are The Alchemists, my friends!:bouquet:3
Elixirコミュニティは本当に優しくて温かい人たちばかり!
私が挫折せずにいられるのもこの恵まれた環境のおかげです。
まずは気軽にコミュニティを訪れてみてください。4

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

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

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

  4. @kn339264さんの素敵なスライドをお借りしました。Elixirコミュニティはいろんな形で活動中!

8
0
0

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
8
0