I ran into the following situation when trying to create a MapSet of MapSets yesterday. If you nest the MapSet.new() calls they get flattened. I don’t know if this is a bug or I am just unaware of the reason this should be the expected behavior. Does anyone have an explanation?
iex(1)> MapSet.new(MapSet.new([1,2]))
#MapSet<[1, 2]>
iex(2)> a = v(1)
#MapSet<[1, 2]>
iex(3)> MapSet.size(a)
2 # ← expected 1
iex(4)> MapSet.put(MapSet.new(), MapSet.new([1,2]))
#MapSet<[#MapSet<[1, 2]>]>
iex(5)> MapSet.size(v(4))
1 # ← this is what I wanted
1 Like
Then what you need is MapSet.new([MapSet.new([1,2])])
That works but it’s weird. I guess if the passed argument is Enumerable the MapSet.new()
call iterates over each item in the passed argument to build the set. So in my original command it’s making a MapSet<[1,2]>, turning it into a list, iterating over that list, and putting each item into a MapSet<[1,2]>. I guess that makes sense. I guess I think it’s a little odd that MapSet.new requires that the passed arg be enumerable. Why is that? Would be nice to say MapSet.new(1) → MapSet<[1]>.
@spec new(Enum.t()) :: t
def new(enumerable)
def new(%__MODULE__{} = map_set), do: map_set
def new(enumerable) do
map =
enumerable
|> Enum.to_list()
|> new_from_list([])
%MapSet{map: map}
end
The enumerable is converted to a list and then each element added to the map set. You can see its implementation here: elixir/map_set.ex at 14dff5c7613d241c29312d73ec1ae001a3c5f7af · elixir-lang/elixir · GitHub
In the case of passing a mapset, there’s an optimization, so no conversion is done.
If you want to create a map of one element, you wrap that element in a list like I did, but if Elixir would work as you suggest, if you want to create a map set of 5 elements, how would Elixir know that MapSet.new([1, 2, 3, 4, 5])
is a a map set of 5 elements or a map set of one element which is a list of length 5?
1 Like
What do you mean if? MapSet.new/1
accepts enumerables only as it can be easily seen from the function spec.
Then it iterates through this Enumerable
, dedups it and produces a MapSet
from unique elements in this Enumerable
.
2 Likes
I’m aware. The rest of the post includes “I think it’s a little odd that MapSet.new requires that the passed arg be enumerable.” @eksperimental explained why it obviously needs to be that way.