具有精确键列表的模式匹配映射

Posted

技术标签:

【中文标题】具有精确键列表的模式匹配映射【英文标题】:Pattern matching map with exact list of keys 【发布时间】:2018-11-14 14:56:43 【问题描述】:

为了验证一些 JSON 文档,我需要确保我的 JSON(表示有一个映射)具有一组特定的字段,不多也不少。

据我所知,与#a := FieldA = MyJSON 之类的模式匹配只能确保密钥a 存在于MyJSON 中。 不幸的是,maps:with/2 会忽略丢失的键,而大多数其他地图功能当时只能在单个键上工作。

在这种情况下,确保地图包含特定字段或字段列表而不包含任何其他字段的推荐方法是什么?

我目前的丑陋解决方案是对我需要的所有键进行模式匹配并重建一个新映射,如下所示:

validate(#a := A, b := B, c := C) ->
#a => A, b => B, c => C.

但它变得非常难以维护,而且很快。

【问题讨论】:

在这些情况下使用record 不是更好吗?或者至少一个记录/元组(或任何其他你事先知道它的结构)你可以检查它。 @ɐuıɥɔɐɯ 我可能会使用 proplist 或元组(这是 sile/jsone 的输出选项)。但是比较两个地图的完全相同的键是一个常见的用例,而且由于尚未实现所有地图功能,我认为它最终会在匹配语法或地图模块中得到支持。 【参考方案1】:

如果我能很好地理解您的问题,这段代码应该可以满足您的需求:

is_map_valid(Map,SortedKeyList) ->
    SortedKeyList == lists:sort(maps:keys(Map)).

在 shell 中测试:

1> Is_map_valid = fun(Map,SortedKeyList) -> SortedKeyList == lists:sort(maps:keys(Map)) end.
#Fun<erl_eval.12.99386804>
2> Map1 = #a => 1, b => 2.                                                                
#a => 1,b => 2
3> Map2 = #a => 1, b => 2, c => 3.
#a => 1,b => 2,c => 3
4> Map3 = #a => 1, b => 2, c => 3, d => 4.
#a => 1,b => 2,c => 3,d => 4
5> Keys = [a,b,c].
[a,b,c]
6> Is_map_valid(Map1,Keys).
false
7> Is_map_valid(Map2,Keys).
true
8> Is_map_valid(Map3,Keys).
false
9>

【讨论】:

【参考方案2】:

如果我理解正确:在maps:with 之后使用maps:size(或erlang:map_size,如果您需要在防护条件下使用),即类似

validate(Keys, Map) -> 
    ExpectedSize = erlang:length(Keys),
    case maps:with(Keys, Map) of
        Map1 when erlang:map_size(Map1) == ExpectedSize -> ok, Map1;
        _ -> invalid
    end.

您也可以先检查Map的大小以快速失败。

【讨论】:

以上是关于具有精确键列表的模式匹配映射的主要内容,如果未能解决你的问题,请参考以下文章

Erlang 映射中的模式匹配键

当用于模式匹配作为映射中的键时,变量是未绑定的

获取 Pandas DataFrame 列中字符串列表中的所有行 - 此模式具有匹配组

如何计算匹配模式的键数?

emacs lisp中关联列表中的匹配键

颤振:将列表值匹配到映射列表键值