czrpb

czrpb

List of Sets: Find Intersecting Sets

This took me way too long and I think its right/working, but .. am I missing a better solution?

defmodule IntersectingSets do
  def meld([], [], [], result) do
    result
  end

  def meld([item|rest], [], [], result) do
    meld(rest, [item], result, [])
  end

  def meld(rest, [item], [], result) do
    meld(rest, [], [], [item|result])
  end

  def meld(rest, [item], [head|tail], result) do
    cond do
      MapSet.intersection(item, head) |> MapSet.size == 0 ->
        meld(rest, [item], tail, [head|result])
      true ->
        meld(rest, [MapSet.union(item, head)], tail, result)
    end
  end

  def meld([item|rest]) do
    meld(rest, [], [], [item])
  end
end

Marked As Solved

mudasobwa

mudasobwa

Creator of Cure

Actually, it might be even simplified. As @saverio-kantox pointed out to me, case is not needed at all. The second clause perfectly does in both cases:

Enum.reduce(sets, [], fn set, sets ->
  {disjoined, joined} =
    Enum.split_with(sets, &MapSet.disjoint?(&1, set))
  [Enum.reduce(joined, set, &MapSet.union/2) | disjoined]
end)

For empty joined, reduce/3 would immediately return the initial accumulator.

Also Liked

al2o3cr

al2o3cr

FWIW, you’ll get much better responses if you describe what this code is supposed to do.

Tracing through an example by hand, it will return the whole input list if every given MapSet intersects with every other one. Non-intersecting sets will be combined.

Some general notes on structure:

  • the second argument is always patterned-matched against either [] or [item]. Consider removing the useless list wrapping and use nil vs item instead

  • +1 to using if over a cond with one non-default branch

  • consider using MapSet.disjoint?/2 - there’s probably a tiny performance benefit to not constructing the whole result of MapSet.intersection, but more importantly it’s clearer what the intent of the check is

kokolegorille

kokolegorille

Why so complicate?

iex> m1 = MapSet.new([1, 2, 3])
#MapSet<[1, 2, 3]>
iex> m2 = MapSet.new([2, 3, 4])
#MapSet<[2, 3, 4]>
iex> MapSet.intersection m1, m2
#MapSet<[2, 3]>

… or maybe I didn’t get what You want

UPDATE: Well, I didn’t get what You want to do… better use data and expected result in that case.
Also, I would not write it like this… first the main entry function, then the rest private…

defmodule Koko do
  def meld(list) do
    ....
  end

  defp do_meld(a, b, c, d) do
    ....
  end
end

With your code, You need to start to read from the bottom.

mudasobwa

mudasobwa

Creator of Cure

You might use Enum.reduce/3 in the following way (untested, but it should work):

Enum.reduce(sets, [], fn set, sets ->
  case Enum.split_with(sets, &MapSet.disjoint?(&1, set)) do
    {_, []} ->  # not a single join, totally alien, appending
      [set | sets]
    {disjoined, joined} ->  # ⇓⇓⇓ here is a trick ⇓⇓⇓
      [Enum.reduce(joined, set, &MapSet.union/2) | disjoined]
  end
end)

The only interesting thing here is that once we discovered all the sets joined the tested one, all of them are to be joined.

Where Next?

Popular in Questions Top

Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a &gt; b) do {:ok, "a"} end if (a &lt; b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
beno
I will often find my self writing things similar to: case some_value do nil -&gt; something() "" -&gt; something() _ -&gt; somethi...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
earth10
Hi, I’m just starting to build a side-project with Elixir and Phoenix and doing some basic test with Elixir alone. What strikes me is th...
New
Tee
can someone please explain to me how Enum.reduce works with maps
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New

Other popular topics Top

josevalim
Hi everyone, One of the features added to Elixir early on to help integration with Erlang code was the idea of overridable function defi...
New
hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a &gt; b) do {:ok, "a"} end if (a &lt; b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 29603 241
New
AstonJ
We’ve put together this wiki for Phoenix LiveView - please feel free to add any info you feel is worth including. What is Phoenix LiveV...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 48342 226
New
Nvim
Anybody knows a comprehensive comparison of Django and Phoenix, thanks for the help. Where are they similar? Where do they differ the m...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New
malloryerik
Hi, this is for people who, like me, have had some friction using .html.heex templates in VSCode. The solution seems to be, in a hyphena...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement