Having problem with list pattern machine in Map

Hello, I have a basic question to improve my self in pattern machine, pleas see this map:

%{ mobile: ["mobile number"] }

if I use For loop , I will be able set this pattern

for {_key, [value]} <- convert_errors do
          IO.inspect value

but I can’t use that without for like this:

{_key, [value]}  =  convert_errors

why does it have this behaviour?

I have tested this yet, but I can’t do what pattern I need without for

  "6f833e1f-be73-4089-91d2-5995e2ec4770": %{"time" => "1544976648"}

by the way, I don’t want to use any Module!


for iterates over a list of elements, which a plain pattern match does not do.

for a when is_atom(a) <- [:a, :b, :c], do: a
# [:a, :b, :c]


[:a | _] = [:a, :b, :c]

If you iterate over a map (similar to iterating over a keyword list) each individual element is a tuple of {key, value}, which is what you’re matching on in your for example.


In this line:

for {_key, [value]} <- convert_errors

there is no pattern matching taking place. The match operator is =, and that line has no = sign in it.

In this line:

{_key, [value]}  =  convert_errors

there is a match operator, but the thing on the left is a tuple and the thing on the right is a map, and a tuple can never match a map. Similarly, the list [1,2,3] can never match the tuple {1, 2, 3}.

To extract values from a map with pattern matching, you need to write:

iex(7)> map = %{ mobile: ["mobile number"] }
%{mobile: ["mobile number"]}

iex(8)> %{mobile: [x]} = map
%{mobile: ["mobile number"]}

iex(11)> x
"mobile number"

It should be noted, it may be some name and be changed, for example

map = %{ mobile: ["mobile number"] }


map = %{ name: ["name string"] }

I want to find the pattern that skips atom name like : mobile and name like this

%{_x: [x]} = map

how can I create a public pattern which can handle both maps.

You can’t.

Just consider %{_ => [x]} were a valid pattern, how would you match %{foo: [:bar], baz: [:quux]}?

1 Like

@NobbZ, thank you , I don’t know how it works, for the sake of this I’m just asking.

I have edited my code like this:

%{_ => value} = %{"mobile" => ["mobile number"] } 

but I have this error:

** (CompileError) iex:2: cannot use variable _ as map key inside a pattern. Map keys in patterns can only be literals (such as atoms, strings, tuples, etc) or an existing variable matched with the pin operator (such as ^some_var)
    (stdlib) lists.erl:1263: :lists.foldl/3

I’m feeling I have no control on my code, I need to have key and value in pattern just for learning.

I have this map in my code

%{"mobile" => ["mobile number"], "family" => ["mobile number"], "name" => ["mobile number"] } 

I assumed if it works, will be helpful for me

Because its not a valid pattern, I used a conjunctive form. A short sentence that should make you clear, that if and only if %{_ => value} were (but it actually is not) valid, then you had a problem with values like %{foo: [:bar], baz: [:quux]}.

1 Like

Thank you, I understood what you was saying, then at last what is your suggestion to handle these maps? using elixir module or for loop to get one map not maps !!?

I usually use Enum or Stream to process such data.

But that totally depends on what kind of processing you want to do.

1 Like

I’m a bit confused here. You say you want to improve your pattern matching skills, but you also seem to have a very specific set of constraints (has to be a for comprehension and the map values have to be a List, (and you don’t want to use any module – which I understand even less)) and a very specific data structure as if you were working on a real problem.

If I’m guessing right, this might be helpful to you

for {_key, values} <- convert_errors, is_list(values), value <- values do

This takes advantage of a lesser known part of for comprehensions called filters. The is_list(values) is the filter that only considers lists. Then after that, we further look at each element of the list.


Thank you for your commenting, Actually I’m trying to improve myself and translate some elixir documents to Persian, For this purpose I saw this problem in my work.
thank you all I will use all of your hints.


for {_key, value} <- convert_errors do
  IO.inspect value

For each tuple {_key, value} which is an element of the collection/enumeration named convert_errors

{_key, [value]}  =  convert_errors

Match the (single) value named convert_errors with the tuple pattern {_key,[value]} pattern, whereupon a successful match the value is destructured according to the pattern and the subvalues are bound to the names _key and value (the leading underscore in _key indicating that the contents bound to the name _key will not be used any further).


i have list =[“admission fee”, “sports fee”], and I want list1 = [title: “admission fee”, title: “sports fee”]

Hello and welcome, You can do it like this…

iex> list = ["admission fee", "sports fee"]
["admission fee", "sports fee"]
iex> Enum.map(list, & {:title, &1})        
[title: "admission fee", title: "sports fee"]
1 Like