如何在不扫描整个 table 的情况下检索 ets 密钥列表?
How to retrieve a list of ets keys without scanning entire table?
我通过 elixir 使用 ets 作为一个简单的内存持久层来存储和检索键,也用于偶尔的 foldl,这涉及减少许多具有不同值的重复键。我正在使用包选项。
是否有一种简单的,也许是 O(1) 的方法来检索仅包含当前键的列表,而不必进行更复杂的 table 遍历或匹配或折叠?
欢迎使用 Erlang 或 Elixir 语法回复。
:ets.new(:cache, [:bag, :named_table, :protected])
我有一个由整数索引的原子键的静态映射,我正在使用它来协助插入。但是并不是所有的键都用上了..
chunk_key_map = %{2 => :chunk_key_2, ..... 28 => :chunk_key_28}
如果没有快速的方法,我知道我可以 ets:lookup 尝试我的每个静态原子键值并测试 != [] 并生成我自己的列表,但想看看是否 ets支持这样的功能。
谢谢
所以我没有找到 ets 技术,而是在 elixir 中以恒定时间实现了键列表检索代码,因为我的键映射是静态的。
list = Enum.reduce(2..28, [], fn head, acc ->
case :ets.lookup(:cache, Map.get(chunk_key_map, head)) do
[] -> acc
_ -> [acc, head]
end
end)
List.flatten(list)
更新:根据回复,我接受了 Hamidreza 的 ets
遍历逻辑并使用 Stream.resource/3
.
将其包装到 Elixir Stream
中
defp get_ets_keys_lazy(table_name) when is_atom(table_name) do
eot = :"$end_of_table"
Stream.resource(
fn -> [] end,
fn acc ->
case acc do
[] ->
case :ets.first(table_name) do
^eot -> {:halt, acc}
first_key -> {[first_key], first_key}
end
acc ->
case :ets.next(table_name, acc) do
^eot -> {:halt, acc}
next_key -> {[next_key], next_key}
end
end
end,
fn _acc -> :ok end
)
end
然后我运行流经管道
get_ets_keys_lazy(table_name)
|> Stream.map(lambda1)
|> Stream.each(lambda2)
|> Stream.run
要获取 ets
中的键列表而不触及它们的值,您可以这样使用 ets:first/1
和 ets:next/2
函数的组合:
-export([keys/1]).
keys(TableName) ->
FirstKey = ets:first(TableName),
keys(TableName, FirstKey, [FirstKey]).
keys(_TableName, '$end_of_table', ['$end_of_table'|Acc]) ->
Acc;
keys(TableName, CurrentKey, Acc) ->
NextKey = ets:next(TableName, CurrentKey),
keys(TableName, NextKey, [NextKey|Acc]).
导出的API为keys/1
。它获取 table 名称,获取它的第一个键,启动一个累加器作为状态并在内部调用 keys/2
获取其他键并以递归方式累积它们。
请注意 bag
table 类型没有顺序,因此如果您的 table 类型是 bag
return 值 keys/1
不会被订购。
谢谢,这让我走上了正确的轨道:)
同样的事情,但将前一个密钥作为累加器传递:
def key_stream(table_name) do
Stream.resource(
fn -> :ets.first(table_name) end,
fn :"$end_of_table" -> {:halt, nil}
previous_key -> {[previous_key], :ets.next(table_name, previous_key)} end,
fn _ -> :ok end)
end
我通过 elixir 使用 ets 作为一个简单的内存持久层来存储和检索键,也用于偶尔的 foldl,这涉及减少许多具有不同值的重复键。我正在使用包选项。
是否有一种简单的,也许是 O(1) 的方法来检索仅包含当前键的列表,而不必进行更复杂的 table 遍历或匹配或折叠?
欢迎使用 Erlang 或 Elixir 语法回复。
:ets.new(:cache, [:bag, :named_table, :protected])
我有一个由整数索引的原子键的静态映射,我正在使用它来协助插入。但是并不是所有的键都用上了..
chunk_key_map = %{2 => :chunk_key_2, ..... 28 => :chunk_key_28}
如果没有快速的方法,我知道我可以 ets:lookup 尝试我的每个静态原子键值并测试 != [] 并生成我自己的列表,但想看看是否 ets支持这样的功能。
谢谢
所以我没有找到 ets 技术,而是在 elixir 中以恒定时间实现了键列表检索代码,因为我的键映射是静态的。
list = Enum.reduce(2..28, [], fn head, acc ->
case :ets.lookup(:cache, Map.get(chunk_key_map, head)) do
[] -> acc
_ -> [acc, head]
end
end)
List.flatten(list)
更新:根据回复,我接受了 Hamidreza 的 ets
遍历逻辑并使用 Stream.resource/3
.
Stream
中
defp get_ets_keys_lazy(table_name) when is_atom(table_name) do
eot = :"$end_of_table"
Stream.resource(
fn -> [] end,
fn acc ->
case acc do
[] ->
case :ets.first(table_name) do
^eot -> {:halt, acc}
first_key -> {[first_key], first_key}
end
acc ->
case :ets.next(table_name, acc) do
^eot -> {:halt, acc}
next_key -> {[next_key], next_key}
end
end
end,
fn _acc -> :ok end
)
end
然后我运行流经管道
get_ets_keys_lazy(table_name)
|> Stream.map(lambda1)
|> Stream.each(lambda2)
|> Stream.run
要获取 ets
中的键列表而不触及它们的值,您可以这样使用 ets:first/1
和 ets:next/2
函数的组合:
-export([keys/1]).
keys(TableName) ->
FirstKey = ets:first(TableName),
keys(TableName, FirstKey, [FirstKey]).
keys(_TableName, '$end_of_table', ['$end_of_table'|Acc]) ->
Acc;
keys(TableName, CurrentKey, Acc) ->
NextKey = ets:next(TableName, CurrentKey),
keys(TableName, NextKey, [NextKey|Acc]).
导出的API为keys/1
。它获取 table 名称,获取它的第一个键,启动一个累加器作为状态并在内部调用 keys/2
获取其他键并以递归方式累积它们。
请注意 bag
table 类型没有顺序,因此如果您的 table 类型是 bag
return 值 keys/1
不会被订购。
谢谢,这让我走上了正确的轨道:)
同样的事情,但将前一个密钥作为累加器传递:
def key_stream(table_name) do
Stream.resource(
fn -> :ets.first(table_name) end,
fn :"$end_of_table" -> {:halt, nil}
previous_key -> {[previous_key], :ets.next(table_name, previous_key)} end,
fn _ -> :ok end)
end