Reputation: 10866
Given a list of items, how may we filter for a specific struct?
Example:
We need only %TL.DocumentAttributeFilename{}
from the items in the list
lst1 = [%TL.DocumentAttributeImageSize{h: 1280, w: 960}, %TL.DocumentAttributeFilename{file_name: "422305695_81769.jpg"}]
lst2 = [%TL.DocumentAttributeVideo{duration: 7, h: 224, w: 264}, %TL.DocumentAttributeFilename{file_name: "animation.gif.mp4"}, %TL.DocumentAttributeAnimated{}]
Upvotes: 1
Views: 3502
Reputation: 17502
You can also use Enum.filter
and pattern match using function with multiple bodies:
list = [%A{number: 1}, %B{number: 2}, %A{number: 3}, %A{number: 4}, %B{number: 5}, %A{number: 6}]
Enum.filter(list, fn
%A{} -> true
_ -> false
end)
This is particularly useful because you can further narrow down using item's properties and guards:
Enum.filter(list, fn
%A{number: n} when n > 4 -> rem(n, 3) == 0
%B{number: n} when n < 2 -> true
_ -> false
end)
Upvotes: 5
Reputation: 992
You can also use Enum.filter
to make it clearer what operation takes place:
Enum.filter( lst1, fn( x ) -> %TL.DocumentAttributeFilename{} == x end )
As Dogbert observed the above expression will keep only those elements of lst1
that are TL.DocumentAttributeFilename
structs with default field values - not what you asked for.
Here's a version that will keep all TL.DocumentAttributeFilename
structs of lst1
:
Enum.filter( lst1, fn( x ) -> x.__struct__ == TL.DocumentAttributeFilename end )
Upvotes: 0
Reputation: 222118
You can use for
for this:
Given:
defmodule A do
defstruct [letter: :a]
end
defmodule B do
defstruct [letter: :b]
end
You can do:
iex(1)> list = [%A{}, %B{}, %A{}, %A{}, %B{}]
[%A{letter: :a}, %B{letter: :b}, %A{letter: :a}, %A{letter: :a}, %B{letter: :b}]
iex(2)> for %A{} = a <- list, do: a
[%A{letter: :a}, %A{letter: :a}, %A{letter: :a}]
This works because for
ignores all items that don't match the given pattern.
Upvotes: 7