Hey, everybody,
couldn’t find a way to get the map from the list.
[1,2,3,4] - source list
%{{1, 2} => true, {3, 4} => true} - the map to which you want to convert
Hey, everybody,
couldn’t find a way to get the map from the list.
[1,2,3,4] - source list
%{{1, 2} => true, {3, 4} => true} - the map to which you want to convert
Can you explain the algorithm you’re looking for here? You want each pair of values as a key?
Let’s start by breaking the problem down: how can you turn [1,2,3,4]
in to pairs of numbers, like [[1,2], [3,4]]
?
The challenge is as follows
the database query returns a list to me
users_pair = [[1, 2], [3, 4]].
I transformed it.
users_pair = List.flatten(users_pair)
then I have to turn it into a map:
map = %{{1, 2} => true, {3, 4} => true}
it requires me to be able to determine if there is such a pair or not, using map[{1,2}].
A list is an ordered collection of value
s.
A map is a key
/value
data structure, you can’t naturally get a map from a list without providing a function which will transform your data.
Looking at your example
The key
s would be a tuple, and the value
s would be the true
As @benwilson512 suggested, you could break the problem and start by trying to get the pairs of values, which will form the keys in the map.
Flattening the list actually moves you further from the solution. Check out https://hexdocs.pm/elixir/List.html#to_tuple/1 and https://hexdocs.pm/elixir/Map.html#new/2
Also Enum.zip/2
looks promising. (Actually even Stream.zip/2
if the length of the list is not known upfront.) Or just for k <- [[1, 2], [3, 4]], into: %{}, do: {k, true}
.
Shouldn’t k be a tuple? In your case it’s a list?!
Is my understanding correct that you need to check if a pair is present in the list? If so, why do you need to transform it in the first place?
I want to get a map that’s cheaper than a search on the list.
If this is the goal, what about:
# make a MapSet out of the pairs
pairs = MapSet.new(users_pair)
# check if a specific pair is in the set:
MapSet.member?(pairs, [3, 4])
# or even:
[3, 4] in pairs
If you only have a small number of pairs, you can use [3, 4] in users_pair
without even turning it into a set, but that will be inefficient if the list gets long.
One caveat: if [1, 2]
and [2, 1]
should be considered the same, you will have to make sure the pairs are always ordered in the same way. Otherwise, MapSet
will consider them as different.
tuple into the map causes an error…
users = [[1, 3], [1, 2], [2, 3], [2, 4], [4, 1]].
tupple = List.to_tuple(users) # [[1, 3], [1, 2], [2, 3], [2, 4], [4, 1]}.
Map.new(users, fn x -> {x, :true} end)
else
users = [[1, 3], [1, 2], [2, 3], [2, 4], [4, 1]].
Map.new(users, fn x -> {x, :true} end)
return
%{
[1, 2] => true,
[1, 3] => true,
[2, 3] => true,
[2, 4] => true,
[4, 1] => true
}
Strictly speaking You could do it like this
iex> list = [1,2,3,4]
iex> for [x, y] <- Enum.chunk_every(list, 2), reduce: %{} do acc -> Map.put(acc, {x, y}, true) end
%{{1, 2} => true, {3, 4} => true}
But many people find it strange as a requirement.
It’s supposed to be a lot of steam. Sorting is done in a model
You are turning the whole list into a tuple. If you want tuples instead of lists for the pairs, you should turn each pair into a tuple instead. Elaborating on my previous answer, this would be the result:
# Make a MapSet of pairs
pairs = MapSet.new([[1, 3], [1, 2], [2, 3], [2, 4], [4, 1]], fn [a, b] -> {a, b} end)
# Check if one pair is in the set
MapSet.member?(pairs, {3, 4})
# Or, equivalently:
{3, 4} in pairs
No need to flatten, turn into a map, etc. if you just want to efficiently test for inclusion in a set. Just use an actual set instead
That said, if this data comes from the database, it’s probably better to write a database query that checks if the pair exists or not, rather than loading all of them and checking that in Elixir, which requires transferring all the pairs and storing them in memory.
Depending on the amount of keys you actually want to look up, it might be a lot cheaper to just do it in the list…
If you only check for 2 or 3 keys, converting the list to a set might even be more expensive than just looking items up in the list.
Not necessarily in terms of algorithmic complexity, but in wall clock time and or memory consumption.
By task, meetings between users are generated once a day, and they must not overlap again.
link to the post where the code is provided (Is there a way to load a complex index from the database into redis?)
I wanted to improve the code so that I wouldn’t make a request to the database every time to check for matches, because the more users there are, the more load it will have.
Thank you, everyone.
These two options work. It should be faster than every time to query the database to check for pairs).
Now I need to see what’s faster of these options and why.)
iex> list = [1,2,3,4]
iex> for [x, y] <- Enum.chunk_every(list, 2), reduce: %{} do acc -> Map.put(acc, {x, y}, true) end
%{{1, 2} => true, {3, 4} => true}
pairs = MapSet.new([[1, 3], [1, 2], [2, 3], [2, 4], [4, 1]], fn [a, b] -> {a, b} end)
MapSet.member?(pairs, {3, 4})