在减少/折叠期间组合数据结构



我正在做一个自然语言处理项目(正在学习Elixir),但无法弄清楚转换数据的惯用方法。

为了不让你厌烦无意义的域详细信息,让我们将问题转移到解析地址上。

给定字符串标记列表,使用相关标记就地组成数据结构,同时将其他标记保留在原处:

# input
["in", "France:",  "22", "Rue", "du", "Débarcadère", ",", "75017", "Paris", ",", "France", "where", "they", "are"]
MyModule.process(tokens)
# output
["in", "France:",  %Address{
street: "Rue du Débarcadère",
street_number: 22,
zip: 75017,
city: "Paris",
country: "France"
}, "where", "they", "are"]
# input
["in", "the", "USA:", "125", "Maiden", "Lane", ",", "11th", "Floor",
"New", "York", ",", "NY", "10038", "USA", "where", "they", "are"]
# output
["in", "the", "USA:",  %Address{
street: "Maiden Lane",
street_number: 125,
floor: 11,
zip: 10038,
city: "New York",
state: "NY",
country: "USA"
}, "where", "they", "are"]

将一系列令牌转换为Address结构将需要一些特定于国家/地区的逻辑(格式化地址的不同方式等),我们假设这些逻辑是可用的。此外,让我们假设我能够通过查看令牌(例如以":"结尾的令牌)切换到适当的解析逻辑(即地址在哪个国家/地区)。

再一次,我想要实现的目标:

  1. 迭代令牌,直到触发特殊情况(国家/地区名称后跟":")
  2. 使用所有相关令牌(在第一个示例中处理从"22"到"France"的令牌)
  3. 将它们替换为结构(%Address{})
  4. 继续迭代第一个未处理的令牌("位置")

某种形式的reduce似乎是合适的,但reduce本身不会继续迭代我想要的地方,而且reduce_while似乎也不是票......

它应该不会有什么不同,但我希望能够在更高级别应用相同的逻辑/过程并编写更高级别的数据结构,例如:

# input
["the", "Mirabeau", "restaurant", "at", %Address{...}, "where", "he", "cooked"]
# output
["the", %Place{
name: "Mirabeau",
type: :restaurant,
location: %Address{...}
}, "where", "he", "cooked"]

您可以使用Stream.unfold/2。将所有令牌作为初始累加器传递,然后从函数中返回一个术语元组和新的累加器。如果国家/地区名称后跟:,您可以根据需要使用任意数量的更多代币并返回剩余的代币。对于其他人,您可以简单地返回头部并继续使用尾部。

这里有一个小例子可以做到这一点:

["in", "France:",  "22", "Rue", "du", "Débarcadère", ",", "75017",
"Paris", ",", "France", "where", "they", "are", "in", "the", "USA:", "125",
"Maiden", "Lane", ",", "11th", "Floor", "New", "York", ",", "NY", "10038",
"USA", "where", "they", "are"]
|> Stream.unfold(fn
[] -> nil
[h | t] ->
if String.ends_with?(h, ":") do
{street, t} = Enum.split_while(t, &(&1 != ","))
["," | t] = t
{rest, t} = Enum.split_while(t, &(&1 <> ":" != h))
[country | t] = t
{%{street: street, rest: rest, country: country}, t}
else
{h, t}
end
end)
|> Enum.to_list
|> IO.inspect

输出:

["in",
%{country: "France", rest: ["75017", "Paris", ","],
street: ["22", "Rue", "du", "Débarcadère"]}, "where", "they", "are", "in",
"the",
%{country: "USA", rest: ["11th", "Floor", "New", "York", ",", "NY", "10038"],
street: ["125", "Maiden", "Lane"]}, "where", "they", "are"]

最新更新