106

This is seemingly simple, but I can't seem to find it in the docs. I need to simply return true or false if an item exists in a list or tuple. Is Enum.find/3 really the best way to do this?

Enum.find(["foo", "bar"], &(&1 == "foo")) != nil
ewH
  • 2,553
  • 2
  • 20
  • 13
  • 2
    For a list I could see where you want to just see if the item is there in which Enum.member?/2 would be a good. But for a tuple you usually care about the position of the value, that is one of the beauties of tuples... might want to consider the usage of a tuple if you don't care about position – CaptChrisD Apr 05 '16 at 15:57
  • You may want to mark @Gazler's answer as the accepted answer if it's right. – Onorio Catenacci Apr 06 '16 at 19:12
  • 1
    Quick note about performance. The `x in y` guard is very performant because it creates different function definitions at compile time. At runtime it's less performant, equivalent to `Enum.member?`, though they're fine to use for small _n_. For large _n_ and tight loops, you'll get better performance from something that hashes, such as `MapSet.member?`. But in most cases, `x in y` and `Enum.member?` are fine! – Dennis May 27 '19 at 21:52

5 Answers5

164

You can use Enum.member?/2

Enum.member?(["foo", "bar"], "foo")
# true

With a tuple you will want to convert to to a list first using Tuple.to_list/1

Tuple.to_list({"foo", "bar"})
# ["foo", "bar"]
Ronan Boiteau
  • 9,608
  • 6
  • 34
  • 56
Gazler
  • 83,029
  • 18
  • 279
  • 245
  • Thanks Gazler. Your answer is correct, but I wanted to post a separate answer based on all of the suggestions I received around the community. – ewH Apr 05 '16 at 22:55
  • 1
    Note that you won't be able to use `Enum.member?/2` inside a guard. In that case, you'll have to rely on `in`. For example: `def foo(string) when string in ["one", "two"], do: IO.puts(string)`. By the way, this is funny, because `in` is a macro that translates to `Enum.member?/2` :D – Alessandro Feb 04 '18 at 22:22
56

Based on the answers here and in Elixir Slack, there are multiple ways to check if an item exists in a list. Per answer by @Gazler:

Enum.member?(["foo", "bar"], "foo")
# true

or simply

"foo" in ["foo", "bar"]
# true

or

Enum.any?(["foo", "bar"], &(&1 == "foo")
# true

or if you want to find and return the item instead of true or false

Enum.find(["foo", "bar"], &(&1 == "foo")
# "foo"

If you want to check a tuple, you need to convert to list (credit @Gazler):

Tuple.to_list({"foo", "bar"})
# ["foo", "bar"]

But as @CaptChrisD pointed out in the comments, this is an uncommon need for a tuple because one usually cares about the exact position of the item in a tuple for pattern matching.

ewH
  • 2,553
  • 2
  • 20
  • 13
37

Or just use in:

iex(1)> "foo" in ["foo", "bar"]
true
iex(2)> "foo" in Tuple.to_list({"foo", "bar"})
true
slashmili
  • 1,190
  • 13
  • 16
2

You can use Enum.find_value/3 too:

iex(1)> Enum.find_value(["foo", "bar"],false, fn(x)-> x=="foo" end)
true

iex(2)> Enum.find_value(["foo", "bar"],false, fn(x)-> x=="food" end)
false
Ronan Boiteau
  • 9,608
  • 6
  • 34
  • 56
Sabit Huraira
  • 307
  • 2
  • 5
2

I started programming in Elixir yesterday, but I will try something I did a lot in JS, maybe it is useful when the list has a lot of elements and you don't want to traverse it all the time using Enum.member?

map_existence = Enum.reduce(list,%{}, &(Map.put(&2,&1,true)))
map_existence[item_to_check]

You can also retrieve an intersection with some other list:

Enum.filter(some_other_list,&(map_existence[&1]))