elixir - 减少一张地图中的地图列表
问题描述
我有一个这样的地图列表:
[
%{"000000000 000000000000 00000000 ": %{}},
%{AM01: %{"C4" => "11111111", "C5" => "1"}},
%{AM04: %{"C2" => "22222222", "C6" => "2"}}
]
如何在一张地图中减少此地图列表,如下所示?
%{
"000000000 000000000000 00000000 ": %{},
AM01: %{"C4" => "11111111", "C5" => "1"},
AM04: %{"C2" => "22222222", "C6" => "2"}
}
生成这个地图列表的代码是这样的:
for segment <- Enum.filter(String.split(message, ["\x02", "\x1d", "\x1e", "\x03"]), fn x -> x != "" end) do
[head | tail] = Enum.filter(String.split(segment, "\x1c"), fn x -> x != "" end)
%{String.to_atom(head) => Map.new(tail, &String.split_at(&1, 2))}
end
解决方案
String.split/2
用于这样的任务是一种极其低效、不优雅和非英语的方法。作为电信的孩子,Erlang(以及 Elixir)在解决这些任务方面特别出色。
它们都将通过递归解析数据、标记上的模式匹配来解决。
由于您没有发布真实输入的示例,因此我无法提出一个可行的示例,但方法应该是:
defmodule Parse do
@input "\x1cHHheader\x1cAAaa segment\x1cBBbbsegment"
def parse("", {{typ, txt}, map}), do: Map.put(map, typ, txt)
def parse(<<"\x1c", type :: binary-size(2), rest :: binary>>, {{typ, txt}, map}),
do: parse(rest, {{type, ""}, Map.put(map, typ, txt)})
def parse(<<c :: binary-size(1), rest :: binary>>, {{typ, txt}, map}),
do: parse(rest, {{typ, txt <> c}, map})
def test(input \\ @input), do: parse(input, {{nil, ""}, %{}})
end
并像这样使用它:
Parse.test
#⇒ %{"AA" => "aa segment", "BB" => "bbsegment", "HH" => "header"}
当然,真正的代码会更复杂,你需要对许多不同的子句进行模式匹配,但我敢打赌这个想法很清楚。
注意我没有测试这段代码,但它应该可以开箱即用。
请注意,这种方法有另一个优势String.split/2
——它能够处理无限流。
推荐阅读
- loops - 带有 2 个变量的 for 循环
- javascript - 这是我一段时间以来一直遇到的错误“找不到模块:无法解析'../lib'”,不知道问题是什么
- flutter - 如何从包含#标签的TextFormField中获取价值并管理它
- python - 访问文件时出现 I/O 错误:/dbfs/my_hyper.hyper: SIGBUS
- sql - 如何使用 COUNT、GROUP BY 和 HAVING 查询的“id”结果来执行另一个只有这些 id 的查询
- css - 如何使用线性渐变在背景中添加多种颜色?
- dart - 如何以双倍显示 X 的完整结果(例如 X=3.45)?
- batch-file - 为什么将命令输出定向到变量在批处理文件中不起作用
- ava - 模拟 AVA 的全局对象
- powershell - PowerShell GUI 自动化——使用 WScript.Shell 从 gui 对话框中获取文本