Search code examples
streamelixirdifferencesubtraction

Subtracting one Stream from the other


In Elixir, you can do the following:

iex> [1,2,3,4] -- [2,3]
[1,4]

Is there an analagous function for Stream types?

Trying to implement this, I have:

  def stream_subtract(enum, []), do: Enum.to_list(enum)

  def stream_subtract(enum1, enum2) do
    head = Stream.take(enum2, 1)
    new_enum1 = Stream.drop_while(enum1, &([&1] == head))
    stream_subtract(new_enum1, Stream.drop(enum2, 1))
  end

however this fails, as [&1] is a list, not a stream.


Solution

  • You will need to collect the second stream ahead of time so that you can test whether an element is present in it. Here's how you'd collect it into a MapSet and then filter the first stream using it.

    Also, Stream.drop_while will only drop from the start of a stream. You need to use Stream.reject if you want to drop from arbitrary positions.

    # Our two streams
    foo = 1..10 |> Stream.take(4)
    bar = 1..10 |> Stream.drop(1) |> Stream.take(2)
    
    # Collect the second stream into a MapSet
    bar = bar |> Enum.into(MapSet.new)
    
    # Filter the first stream and print all items:
    foo = foo |> Stream.reject(fn x -> x in bar end)
    for f <- foo, do: IO.inspect(f)
    

    Output:

    1
    4