Sanjibukai

Sanjibukai

Is it possible to partially pattern-match Lists as we do with Maps?

Hello everybody,

As it’s possible to partially pattern match with maps like so:

iex> %{b: 2} = %{a: 1, b: 2, c: 3}
%{a: 1, b: 2, c: 3}

Is it possible to do the same with Lists, e.g. like that:

iex> [2] = [1, 2, 3]
# MatchError

I guess that the inherent nature of linked lists (which make it easy to pattern-match heads/tails) might complicate things. Also I got the fact that in this case it might not make sense to pattern-match for variable binding . But it might be useful to pattern-match in this case for conditions/tests.

One can simply use Enum.member? but I don’t see an easy way to avoid conditions like we do when using pattern-matching in general or in functions argument.

Thank you very much for any details…

Marked As Solved

lucaong

lucaong

Or even easier, as you can use it in guards:

def some_func(x) when x in [1, 2, 3] do
  :present
end

def some_func(_) do
  :not_present
end

Also Liked

NobbZ

NobbZ

Yeah, this different implemantation introduces slightly “bugs” if not understood correctly:

def f(x) when x in [1,2,3], do: "123"
def f(x) when x in 4..6, do: "456"
def f(_), do: "nope"

IO.puts f(2) #=> 123
IO.puts f(2.0) #=> nope
IO.puts f(2.5) #=> nope
IO.puts f(5) #=> 456
IO.puts f(5.0) #=> 456
IO.puts f(5.5) #=> 456
benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

Hi @Sanjibukai you can match on the head and tail of a list, but there is no way to do a match which asks “Is this value anywhere in the list”.

[head | tail] = [1,2,3]
head #=> 1
tail #=> [2,3]
lucaong

lucaong

As @benwilson512 said, you cannot pattern match in the middle of a list. If you are looking for a convenient and readable way to check for inclusion, you can do this though:

2 in [1, 2, 3]

You can also use it in guards:

case 2 do
  x when x in [1, 2, 3] -> :yes
  _ -> :no
end
lucaong

lucaong

It’s interesting to notice how the guard is implemented. It is documented here and basically translates this:

when x in [1, 2, 3]

Into this:

when x === 1 or x === 2 or x === 3

The guard also works for ranges, with a different implementation, as the documentation shows.

lucaong

lucaong

Important thing to notice in order to understand the behavior of in with ranges, is that a range is an Enumerable of integers. Therefore, (0..10) includes 5 but not 5.5, nor 5.0 (see the is_integer(x) in the guard expansion).

That is consistent with how Enum.member? works on ranges:

Enum.member?(0..10, 5) #=> true
Enum.member?(0..10, 5.5) #=> false
Enum.member?(0..10, 5.0) #=> false

In other words, it could be considered surprising, but it is not a bug, it is intended behavior.

Where Next?

Popular in Questions Top

pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: https://hexdocs.pm/ecto/Ecto.Schema.html#module-...
New
Kagamiiiii
Student & New to elixir. Nice language. I want to convert a english character, e.g. “a”, which is stored in a variable, to it’s asci...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
mathew4509
I have a list say x = ["23gh", "56kh", "97mh"] I would like to pass each element to Val in each iteration. Say, in iteration 1 -------...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
Exadra37
Sometimes I want to check if the input into a function is not a blank string. My first approach: defmodule Example do def do_stuff(s...
New
jc00ke
Expanding on this topic: https://forum.elixirforum.net/t/map-typespec-question/19217 Let’s say I have a map with required and optional k...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New

Other popular topics Top

shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
polypush135
As many of you may have realized by now (sorry for all the posts here) I’ve been working on a db problem where I’m trying to aggregate a ...
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers' Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
lucidguppy
I have a super simple question about elixir - how would I take a file like this foo bar baz and output a new file that enumerates th...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

We're in Beta

About us Mission Statement