minhajuddin
Is there a simpler way to generate ids
I am using the code below to generate room ids:
reservations = [%{rooms: 1},
%{rooms: 2},
%{rooms: 3}]
{reservations_with_room_numbers, _} =
Enum.reduce(reservations, {[], 0}, fn reservation, {acc, offset} ->
upper_limit = offset+reservation.rooms - 1
room_numbers = Enum.to_list(offset..upper_limit)
reservation_with_room_numbers = Map.put(reservation, :room_numbers, room_numbers)
{[reservation_with_room_numbers|acc], upper_limit + 1}
end)
IO.inspect Enum.reverse(reservations_with_room_numbers)
# =>
# [
# %{room_numbers: [0], rooms: 1}
# %{room_numbers: [1, 2], rooms: 2},
# %{room_numbers: [3, 4, 5], rooms: 3},
# ]
The code above seems too complicated for such a simple task, Is there a simpler way to do the same?
System.unique_integer [:monotonic, :positive] gives out unique integers starting at 1, However there is no way to reset it after the generation is done, so that it starts from 1 for the next call.
Marked As Solved
josevalim
I believe your initial solution looks good, I would just use map_reduce instead of reduce to clean things up:
reservations = [%{rooms: 1},
%{rooms: 2},
%{rooms: 3}]
{reservations_with_room_numbers, _} =
Enum.map_reduce(reservations, 0, fn reservation, offset ->
upper_limit = offset+reservation.rooms - 1
room_numbers = Enum.to_list(offset..upper_limit)
reservation_with_room_numbers = Map.put(reservation, :room_numbers, room_numbers)
{reservation_with_room_numbers, upper_limit + 1}
end)
Also Liked
JEG2
Or, with a generator:
defmodule Generator do
def new(start) do
Agent.start_link(fn -> start end)
end
def next(generator) do
Agent.get_and_update(generator, fn value -> {value, value + 1} end)
end
end
defmodule RoomBuilder do
def build([{:rooms, n} | rooms], built, generator) do
room_numbers =
Stream.repeatedly(fn -> Generator.next(generator) end)
|> Enum.take(n)
build(rooms, [room_numbers | built], generator)
end
def build([ ], built, _generator), do: Enum.reverse(built)
end
{:ok, generator} = Generator.new(0)
reservations = [rooms: 1, rooms: 2, rooms: 3]
RoomBuilder.build(reservations, [ ], generator)
|> IO.inspect
benwilson512
One thing that isn’t clear is if we want a pure or impure solution. The original post had both. They’re wildly different solutions and people need to be aware of that.
michalmuskala
I believe this shows another use case for a function like Stream.split/2 - similar to Enum.split/2, but one that would leave the “rest” part as a stream. This would allow for the most natural way to solve this:
ids = Stream.itrerate(1, &(&1 + 1))
Enum.map_reduce(reservations, ids, fn reservation, ids ->
{room_numbers, rest} = Stream.split(ids, reservation.rooms)
{Map.put(reservation, :room_numbers, room_numbers), rest}
end) |> elem(0)







