ELIXIR:如何筛选特定结构的列表

时间:2016-04-29 11:08:23

标签: list pattern-matching elixir

给定项目列表,我们如何过滤特定结构?

示例:

我们只需要列表中项目的%TL.DocumentAttributeFilename{}

 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{}]

3 个答案:

答案 0 :(得分:7)

您可以使用for

假设:

defmodule A do
  defstruct [letter: :a]
end

defmodule B do
  defstruct [letter: :b]
end

你可以这样做:

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}]

这是有效的,因为for忽略了与给定模式不匹配的所有项目。

答案 1 :(得分:1)

您还可以使用Enum.filter并使用具有多个主体的函数进行模式匹配:

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)

这特别有用,因为您可以使用项目的属性和防护进一步缩小范围:

Enum.filter(list, fn
  %A{number: n} when n > 4 -> rem(n, 3) == 0
  %B{number: n} when n < 2 -> true
  _ -> false
end)

答案 2 :(得分:0)

您还可以使用Enum.filter更清楚地执行操作:

Enum.filter( lst1, fn( x ) -> %TL.DocumentAttributeFilename{} == x end )

正如Dogbert观察到的那样,上面的表达式只会保留lst1 TL.DocumentAttributeFilename结构中具有默认字段值的元素 - 而不是您要求的内容。

这是一个保留TL.DocumentAttributeFilename所有lst1结构的版本:

Enum.filter( lst1, fn( x ) -> x.__struct__ == TL.DocumentAttributeFilename end )