First of, thank you for creating and maintaining this great library!
I think there is a missing primitive which I needed quite often when writing generators: take_from(bag, amount)
Sample usage:
cards = [:jack, :queen, :king, :ace, 2, 3, 4, 5, 6, 7, 8, 9, 10]
check all(
{hand_p1, remaining} <- take_from(cards, 2),
{hand_p2, _remaining} <- take_from(remaining, 2)
) do
# assert some poker logic
end
I think this should be in the library, since I struggled quite a bit with implementing it myself.
First I tried this horrible mess:
It works, but throws StreamData.TooManyDuplicatesError quite often.
defp take_from(bag, n) do
indexed_bag =
Enum.with_index(bag)
StreamData.uniq_list_of(StreamData.one_of(indexed_bag |> Enum.map(&StreamData.constant/1)),
length: n
)
|> StreamData.map(fn indexed_items ->
{taken_items, taken_indexes} =
Enum.unzip(indexed_items)
taken_indexes = MapSet.new(taken_indexes)
new_bag =
indexed_bag
|> Enum.reject(fn {_, i} -> MapSet.member?(taken_indexes, i) end)
|> Enum.map(&elem(&1, 0))
{new_bag, taken_items}
end)
end
I then improved it quite a bit with this recursive version:
defp take_from(bag, n), do: do_take_from(bag, n, [])
defp do_take_from(bag, 0, acc), do: StreamData.constant({acc, bag})
defp do_take_from(bag, n, acc) do
StreamData.one_of(Enum.with_index(bag) |> Enum.map(&StreamData.constant/1))
|> StreamData.bind(fn {item, i} ->
new_bag = List.delete_at(bag, i)
do_take_from(new_bag, n - 1, [item | acc])
end)
end
But I still think there could be a better version, probably one that would use Enum.take_random/2.
But I can't figure it out.
Any ideas? Could we get this into the library?
First of, thank you for creating and maintaining this great library!
I think there is a missing primitive which I needed quite often when writing generators:
take_from(bag, amount)Sample usage:
I think this should be in the library, since I struggled quite a bit with implementing it myself.
First I tried this horrible mess:
It works, but throws
StreamData.TooManyDuplicatesErrorquite often.I then improved it quite a bit with this recursive version:
But I still think there could be a better version, probably one that would use
Enum.take_random/2.But I can't figure it out.
Any ideas? Could we get this into the library?