首先,我绝对相信我会以错误的方式解决这个问题,因为我还在学习来自Ruby的Elixir ......
我从youtube获取搜索结果列表,并尝试提取视图最多的视频.
# html is the contents of the search results page
metas = html |> Floki.find(".yt-lockup-meta-info > li")
counter = -1
index = -1
high_views = 0
Enum.each(metas, fn(li) ->
counter = counter + 1
text = Floki.text(li)
case String.split(text, " ") do
[count, "views"] ->
views = String.to_integer(String.replace(count, ",", ""))
IO.puts(">>> #{counter} - #{to_string(views)} views")
if views > high_views do
high_views = views
index = counter
end
[age, time_measurement, "ago"] ->
nil
end
end)
Run Code Online (Sandbox Code Playgroud)
metas是一个li元组列表,如下所示:
[{"li", [], ["2 years ago"]}, {"li", [], ["5,669,783 views"]},
{"li", [], ["9 years ago"]}, {"li", [], ["17,136,804 views"]},
...
{"li", [], ["1 year ago"]}, {"li", [], ["15,217 views"]},
{"li", [], ["8 years ago"]}, {"li", [], ["909,053 views"]}]
Run Code Online (Sandbox Code Playgroud)
这不起作用,因为传递给的匿名函数Enum.each有自己的作用域,并且没有为index和设置值high_views.
有没有办法将值从外部范围传递到匿名函数?或者更好的问题是,我该怎么做呢?
我打算让它工作,然后重构代码,但我卡住了.谢谢你的帮助.
Elixir是不变的.该函数是一个闭包,因此外部变量在那里可见,但你不能改变它们.您只能重新绑定它们,但重新绑定将保留在内部的匿名函数范围内.
但是你正在尝试做的工具都在Enum模块中.
您实际上是在寻找具有最大视图的索引.让我们看看Enum函数.Enum.max_by/2看起来很有希 它需要一个枚举和一个返回我们想要最大值的函数.我将它配对Enum.with_index/1,它接受一个列表,并使用该元素的索引将每个元素包装在一个元组中.
metas
|> Enum.with_index
|> Enum.max_by(fn {li, index} ->
text = Floki.text(li)
case String.split(text) do # (splits on whitespace by default)
[count, "views"] ->
views = count |> String.replace(",", "") |> String.to_integer
IO.puts ">>> #{index} - #{views} views"
views
_ -> -1
end
end)
Run Code Online (Sandbox Code Playgroud)
与您的实现的主要区别在于内部函数根据其参数返回一个值,而不是尝试改变外部状态.
我把"无所事事"的情况折叠成一个简单的全能_,并假设youtube视频没有负视图计数返回-1.您的示例的直接转换将在此处返回零(您的初始值high_views).这也许是安全的.