Elixir等函数式语言如何过滤嵌套子数组并保留外层结构
问题描述
当前使用Elixir开发,该解决思路同样适用于所有函数式语言。需求为处理可能嵌套JSON子数组的JSON数组,需要实现两类效果:
- 筛选出子数组中符合特定值条件的元素
- 若筛选后子数组中至少剩余1个元素,则保留对应的外层数组元素
示例
输入
decisions = [%{ "name" => "Only for B", "chance" => 0, "modifiers" => [%{ "position" => 0, "match" => "B", "weight" => 0 }, %{ "position" => 0, "match" => "C", "weight" => 1 } ] }]
期望输出
移除所有weight字段不为0的元素,完整保留外层结构:
expected_result = [%{ "name" => "Only for B", "chance" => 0, "modifiers" => [%{ "position" => 0, "match" => "B", "weight" => 0 }] }]
实际错误输出
外层数组结构丢失,仅返回筛选后的子数组:
actual_result = [[%{ "position" => 0, "match" => "B", "weight" => 0 }]]
问题原因
当前编写的代码如下:
def modifiers_with_certainty(decisions) do Enum.map(decisions, fn decision -> Enum.filter(decision["modifiers"], fn modifier -> modifier["weight"] == 0 end) end) end
现有代码的核心错误是:外层Enum.map直接返回了内层筛选后的modifiers子数组,没有把筛选结果塞回原外层decision的结构里,自然会丢失name、chance这些外层字段。如果外层直接换用Enum.filter也无法实现需求,因为filter只能决定当前元素留不留,没法修改元素内部的子数组内容。
解决方案
实现逻辑分两步:
- 对每个外层元素,先筛选内部的
modifiers子数组,再将筛选后的子数组更新回原外层元素结构,保留其他所有字段 - 丢弃所有筛选后
modifiers子数组为空的外层元素
可以用Enum.flat_map一次性遍历完成两个操作,代码如下:
def modifiers_with_certainty(decisions) do Enum.flat_map(decisions, fn decision -> # 先筛选内层子数组 filtered_modifiers = Enum.filter(decision["modifiers"], &(&1["weight"] == 0)) if Enum.empty?(filtered_modifiers) do # 子数组为空则丢弃该外层元素 [] else # 子数组非空则返回更新后的外层结构 [%{decision | "modifiers" => filtered_modifiers}] end end) end
如果更偏好分步的可读写法,也可以先map更新结构,再filter丢弃空元素,逻辑完全等价:
def modifiers_with_certainty(decisions) do decisions |> Enum.map(fn decision -> filtered_modifiers = Enum.filter(decision["modifiers"], &(&1["weight"] == 0)) %{decision | "modifiers" => filtered_modifiers} end) |> Enum.filter(&(length(&1["modifiers"]) > 0)) end
内容的提问来源于stack exchange,提问作者Jules
相关产品推荐
相关产品推荐

