6

我通过 elixir 使用 ets 作为一个简单的内存持久层来存储和检索键,也用于偶尔的 foldl,这涉及减少许多具有不同值的重复键。我正在使用包选项。

是否有一种简单的,可能是 O(1) 的方法来检索仅包含当前键的列表,而无需进行更复杂的表遍历或匹配或折叠?

欢迎 Erlang 或 Elixir 语法响应。

:ets.new(:cache, [:bag, :named_table, :protected])

我有一个由整数索引的原子键的静态映射,用于协助插入。但并不是所有的键都被使用..

chunk_key_map = %{2 => :chunk_key_2, ..... 28 => :chunk_key_28}

如果没有快速的方法,我知道我可以做一个 ets:lookup 尝试我的每个静态原子键值并测试 != [] 并生成我自己的列表,但想看看 ets 是否支持这样的功能。

谢谢

4

3 回答 3

5

谢谢,这让我走上了正确的轨道:)

同样的事情,但将前一个键作为累加器传递:

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
于 2017-05-08T08:17:04.353 回答
2

所以我没有找到 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 遍历逻辑并将其包装到 ElixirStream中,使用Stream.resource/3.

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
于 2016-02-01T05:50:09.943 回答
2

ets要在不触及其值的情况下获取键列表,您可以通过以下方式使用ets:first/1ets: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. 它获取表名,获取它的第一个键,启动一个累加器作为状态,并在内部调用keys/2它获取其他键并以递归方式累加它们。

请注意,bag表格类型没有顺序,因此如果您的表格类型是bag的返回值keys/1不会被排序。

于 2016-02-01T08:00:16.553 回答