LoginSignup
7
0

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

Last updated at Posted at 2023-12-24

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

目的

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

実行環境

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.map

第一引数の要素を順番に取り出す。
取り出した各要素に第二引数の関数処理をする。

お手本の写経

iex
Enum.map(cart, & &1.fruit)
["apple", "banana", "orange"]
iex
Enum.map(cart, fn item ->
  %{item | count: item.count + 10}
end)
[%{count: 13, fruit: "apple"}, %{count: 11, fruit: "banana"}, %{count: 16, fruit: "orange"}]

自分のケースでの演習

iex
Enum.map(users, & &1.name) 
["santa", "reindeer", "dwarf"]
iex
users 
|> Enum.map(fn user -> %{user | age: user.age + 10} end)
[
  %Dec23.Users.User{
    __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
    id: 1,
    name: "santa",
    age: 110, #10歳増えた
    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: 65, #10歳増えた
    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: 49, #10歳増えた
    inserted_at: ~U[2023-12-23 09:07:44Z],
    updated_at: ~U[2023-12-23 09:07:44Z]
  }
]

Enum.map_every

第一引数に0ベースでインデックスを振る。
第一引数の要素を順番に取り出す。
取り出した各要素のうち、インデックスが第二引数の倍数ごとに、要素に対して第三引数の関数処理をする。1
但し最初の要素は必ず関数処理をする。

お手本の写経

iex
Enum.map_every(cart, 2, fn item ->
  %{item | count: item.count + 10}
end)
[%{count: 13, fruit: "apple"}, %{count: 1, fruit: "banana"}, %{count: 16, fruit: "orange"}]
iex
Enum.map_every(1..10, 3, fn x -> x + 1000 end)
[1001, 2, 3, 1004, 5, 6, 1007, 8, 9, 1010] #最初の要素と3の倍数のインデックスに対して関数処理をしている

自分のケースでの演習

iex
iex(34)> Enum.map_every(users, 2, fn user -> %{user | age: user.age + 10} end) 
[
  %Dec23.Users.User{
    __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
    id: 1,
    name: "santa",
    age: 110, #最初の要素は必ず関数処理をする
    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: 49, #0ベースインデックスで2番目の要素なので関数処理をする
    inserted_at: ~U[2023-12-23 09:07:44Z],
    updated_at: ~U[2023-12-23 09:07:44Z]
  }
]

内包表記(for文)

<- の右側の要素を順番に取り出す。
取り出した各要素にdo endブロック内の処理をする。

お手本の写経

iex
for item <- cart do
  item.fruit
end
["apple", "banana", "orange"]

自分のケースでの演習

iex
for user <- users do
  user.name
end
["santa", "reindeer", "dwarf"]

内包表記(for文)とfilteringの合わせ技

<- の右側の要素を順番に取り出す。
doの前に書かれた条件にヒットした要素にのみ絞り込み、do endブロック内の処理をする。

お手本の写経

iex
for item <- cart, item.fruit =~ "e" do
  item.fruit
end
["apple", "orange"]

自分のケースでの演習

iex
for user <- users, user.name =~ "a" do
  user.name
end
["santa", "dwarf"]

~Elixirの国のご案内~

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

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

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

  1. 世界のナベアツ的なイメージ?インデックスが3だったら、要素が3つ飛びに関数処理が入るイメージ。1,2,「サン!」, 4, 5, 「ロク!」みたいな?(ネタが古い(;'∀'))

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

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

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