Practical difference between Erlang maps:remove/2 and maps:without/2

这一生的挚爱 提交于 2019-12-07 19:49:46

问题


Checking over the documentation for one of the new R17 features, maps, brought me to maps:remove/2 and maps:without/2. The only clear distinction I can see is that remove/2 takes a single key and returns a view of the map without it, where without/2 accepts a list and returns a completely new map lacking the listed keys.

22> M1 = #{foo => bar, spam => eggs}.
#{foo => bar,spam => eggs}
23> M2 = maps:without([foo], M1).
#{spam => eggs}
24> M3 = maps:remove(foo, M1).
#{spam => eggs}
25> M1.
#{foo => bar,spam => eggs}
26> M2.
#{spam => eggs}
27> M3.
#{spam => eggs}

What is the practical impact of this? I can appreciate not wanting to create in-memory copies of gigantic maps with without/2, but why doesn't remove/2 accept a list? I'm assuming there is a performance-oriented reason why these two functions exist the way they do, but I'm confused about when I would want to use one over the other in most situations (meaning, I don't think that maintaining gigantic maps are a generally good idea).


回答1:


The first thing about maps is that, the implementation may change. As Fred Hébert wrote in learn you some Erlang maps Chapter: "The OTP team is respecting the old slogan: first make it work, then make it beautiful, and only if you need to, make it fast." So don't depend on this answer too heavily.

Currently the maps:without/2 function is implemented like this:

without(Ks, M) when is_list(Ks), is_map(M) ->
    maps:from_list([{K,V}||{K,V} <- maps:to_list(M), not lists:member(K, Ks)]).

As you can see, it iterates over entire map. It converts it to list, removes the keys and converts it back to map. Not really efficient, but as I said: this may change in the future.

The maps:remove/2 function is a NIF, which means, it is written in C and takes advantage from internal representation. Speaking of which... During Stockholm Erlang Factory 2013 Kenneth Lundin mentioned maps internal representation (http://vimeo.com/69950294). Actually, there are two of them (sliedes are from the talk, that I linked to).

This one is for low amount of keys. In this representation, set of values has pointer to set of keys, which means, that if you change value, but not the key - keys will be shared. Also keys are sorted. Second one, for larger amounts of keys looks like this:

So it is a tree, which means, that if you for example delete a key on the right subtree, your new map could share entire left subtree. For more clear information on immutable data structures, you can refer to wikipedia ErlangVM should transparently switch between those representations as needed.

To answer your question. If you want to delete one key - use maps:remove/2, if you want to delete multiple keys, use maps:without/2, because it might be cheaper to create new map instead of manipulating the old one.



来源:https://stackoverflow.com/questions/25779783/practical-difference-between-erlang-mapsremove-2-and-mapswithout-2

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!