Padding a list

974 views
Skip to first unread message

eksperimental

unread,
Sep 19, 2015, 5:51:57 AM9/19/15
to elixir-l...@googlegroups.com
How can zip two lists and pad them with a default value if the second
list is shorter than the first one?


iex> animals = [:cat, :deer, :dog, :mouse, :elephant]
iex> group = [:feline, nil, :canine]
iex> Enum.zip(animals, group)
[cat: :feline, deer: nil, dog: :canine]

What I need to generate is:
[cat: :feline, deer: nil, dog: :canine, mouse: nil, elephant: nil]

is there an padding function that i can apply to `group`, so it can
have the remaining of the elements set to nil.
?

thank you

José Valim

unread,
Sep 19, 2015, 5:56:32 AM9/19/15
to elixir-l...@googlegroups.com
I don't think there is a function for it right now. I would love to add something like zip_all or zip_with_padding or simply zip/3 (if we are copying chunk signature). The tricky part is exactly in finding a name.



José Valim
Skype: jv.ptec
Founder and Director of R&D


--
You received this message because you are subscribed to the Google Groups "elixir-lang-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-ta...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-talk/20150919165148.6a14faf3.eksperimental%40autistici.org.
For more options, visit https://groups.google.com/d/optout.

eksperimental

unread,
Sep 19, 2015, 6:02:45 AM9/19/15
to elixir-l...@googlegroups.com
thanks for the answer José,

yes, we should have something like this.

So, what would be the approach to tackle this?


On Sat, 19 Sep 2015 11:56:08 +0200
José Valim <jose....@plataformatec.com.br> wrote:

> I don't think there is a function for it right now. I would love to
> add something like zip_all or zip_with_padding or simply zip/3 (if we
> are copying chunk signature). The tricky part is exactly in finding a
> name.
>
>
>
> *José Valim*

José Valim

unread,
Sep 19, 2015, 6:03:47 AM9/19/15
to elixir-l...@googlegroups.com
1. Find a good name/arity
2. Agree on good name/arity
3. Send a PR

:)



José Valim
Skype: jv.ptec
Founder and Director of R&D

eksperimental

unread,
Sep 19, 2015, 6:07:25 AM9/19/15
to elixir-l...@googlegroups.com
sorry, by tackling this, i was referring to my original example.

On Sat, 19 Sep 2015 12:03:25 +0200
José Valim <jose....@plataformatec.com.br> wrote:

> 1. Find a good name/arity
> 2. Agree on good name/arity
> 3. Send a PR
>
> :)
>
>
>

José Valim

unread,
Sep 19, 2015, 6:09:41 AM9/19/15
to elixir-l...@googlegroups.com
You can hand roll your own zip. here is an implementation that assumes both functions have the same size in Erlang:


And here is Elixirs:


Let me know if you want a more detailed solution :)



José Valim
Skype: jv.ptec
Founder and Director of R&D

eksperimental

unread,
Sep 19, 2015, 7:57:22 AM9/19/15
to elixir-l...@googlegroups.com
Thanks a lot for the guidance.

Here's my hand-rolled version
https://github.com/eksperimental/experimental_elixir/blob/master/lib/enum_zip_pad.ex
https://github.com/eksperimental/experimental_elixir/blob/master/test/enum_zip_pad.exs

this version if either one is shorter it will fill it with either
padding1 or padding2

What would be the best way to design the API so it can fill,
- only `collection1` if needed
- only `collection2` if needed
- both (my currect implementation).


On Sat, 19 Sep 2015 12:09:21 +0200
José Valim <jose....@plataformatec.com.br> wrote:

> You can hand roll your own zip. here is an implementation that
> assumes both functions have the same size in Erlang:
>
> https://github.com/erlang/otp/blob/maint/lib/stdlib/src/lists.erl#L386-L387
>
> And here is Elixirs:
>
> https://github.com/elixir-lang/elixir/blob/master/lib/elixir/lib/enum.ex#L2577-L2582
>
> Let me know if you want a more detailed solution :)
>
>
>

eksperimental

unread,
Sep 19, 2015, 8:19:20 AM9/19/15
to elixir-l...@googlegroups.com
Amazing how in the erlang version, the spec is twice longer that the
function itself!

On Sat, 19 Sep 2015 12:09:21 +0200
José Valim <jose....@plataformatec.com.br> wrote:

> You can hand roll your own zip. here is an implementation that
> assumes both functions have the same size in Erlang:
>
> https://github.com/erlang/otp/blob/maint/lib/stdlib/src/lists.erl#L386-L387
>
> And here is Elixirs:
>
> https://github.com/elixir-lang/elixir/blob/master/lib/elixir/lib/enum.ex#L2577-L2582
>
> Let me know if you want a more detailed solution :)
>
>
>

eksperimental

unread,
Sep 19, 2015, 2:40:12 PM9/19/15
to elixir-l...@googlegroups.com
And here's the Enum.pad/3 function if anyone's interested.

https://github.com/eksperimental/experimental_elixir/blob/master/lib/enum_pad.ex
https://github.com/eksperimental/experimental_elixir/blob/master/test/enum_pad_test.exs

rigth now Enum.pad/3 and Enum.zip_pad/4 work only with lists, (so they
are more like List.pad and List.zip_pad)

I should add support for streams soon.

Tallak Tveide

unread,
Sep 21, 2015, 2:39:33 AM9/21/15
to elixir-lang-talk, eksper...@autistici.org

I am thinking `zip/3` or `pad_zip` rather than `zip_pad`, because you are first padding then zipping.

The `pad` parameter of `Enum.chunk` is an enumerable, I think this would make sense for `zip` as well.

If I were to suggest a syntax, it could be:

```
Enum.zip 1..3, 5..8, Stream.cycle([nil])
Enum.zip 1..3, 5..8, pad_left: [nil]
Enum.zip 1..3, 5..8, pad_right: [nil]
Enum.zip 1..3, 5..8, pad_left: [nil], pad_right: [nil]
```

You would only pick items from the `pad` on need, and zipping would stop if the pad was empty.

If the third parameter is an Enumerable, both left and right may be padded. If it is a keyword list, the left and right arguments are padded by `pad_left` and `pad_right` respectively.

I think an implementation for the standard library should travese the two enumerables only once for efficiency. I could look into making an implementation suggestion later (after my holidays, a few weeks from now).



eksperimental

unread,
Sep 26, 2015, 1:09:22 PM9/26/15
to elixir-l...@googlegroups.com
Hi Tallak,
I have implemented a new version taking into consideration your
advices. It really helped me with the decision. I ended up with
Enum.pad/3 and Enum.pad_zip/3 & /4

Enum.pad_zip leverages all the work to Enum.pad,
and once the two enumerables are padded, it is just a matter of calling
Enum.zip/2 for a regular zipping operation.

So the padding in Enum.pad and Enum.pad_zip can only an enumerable or
a function with arity of 1.
No options are required, just good old plain arguments.

Here are some examples from the docs:

## Enum.pad/3
# Enum.pad(enum, size, pad)

# default padding
iex> Enum.pad([1, 2, 3], 5)
[1, 2, 3, nil, nil]

# not enought padding
iex> Enum.pad([1, 2, 3], 5, [nil])
[1, 2, 3, nil]

# functions
iex> Enum.pad([1, 2, 3], 5, &(&1+10))
[1, 2, 3, 13, 23]

# ranges
iex> Enum.pad([1, 2, 3], 6, 50..100)
[1, 2, 3, 50, 51, 52]

# Stream.cycle
iex> Enum.pad([1, 2, 3], 10, Stream.cycle([0, 1]))
[1, 2, 3, 0, 1, 0, 1, 0, 1, 0]


## Enum.pad_zip/3 and Enum.pad_zip/4
# Enum.pad_zip(enum1, enum2, pad1, pad2)

# default pad_zip
iex> Enum.pad_zip(1..5, [:a])
[{1, :a}, {2, nil}, {3, nil}, {4, nil}, {5, nil}]

# Stream.cycle as two differnt paddings
iex> Enum.pad_zip(1..5, [:a, :b, :c], Stream.cycle([0]),
...> Stream.cycle([:z]))
[{1, :a}, {2, :b}, {3, :c}, {4, :z}, {5, :z}]

# a bit more complex function as padding
iex> Enum.pad_zip([:a, :aN], 1..4, &("#{&1}" |> String.reverse
...> |> String.duplicate(2) |> String.to_atom))
[a: 1, aN: 2, NaNa: 3, aNaNaNaN: 4]

You can find the sources here:
https://github.com/eksperimental/experimental_elixir/blob/master/lib/enum_pad.ex
https://github.com/eksperimental/experimental_elixir/blob/master/test/enum_pad_test.exs

Regards,
- eksperimental


On Sun, 20 Sep 2015 23:39:33 -0700 (PDT)
Tallak Tveide <tal...@gmail.com> wrote:

>
> I am thinking `zip/3` or `pad_zip` rather than `zip_pad`, because you
> are first padding then zipping.
>
> The `pad` parameter ofum.chunk` is an enumerable, I think this

Tallak Tveide

unread,
Sep 27, 2015, 12:28:44 PM9/27/15
to elixir-l...@googlegroups.com
Hmm. Short on time but browsing through your code, i dont think you should be using Enum.take to check if it is enumerable. The reason is that an enumerable may have side effects, eg when reading from a file.

From what ive seen, elixir will have speciality implementations for some types, eg lists, then just assume that the argument supports any syntax/semantics that you would need from enumerables.



Sendt fra min telefon
> --
> You received this message because you are subscribed to a topic in the Google Groups "elixir-lang-talk" group.
> To unsubscribe from this topic, visit https://groups.google.com/d/topic/elixir-lang-talk/pil9caRXQnM/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to elixir-lang-ta...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-talk/20150927000908.299bf8b7.eksperimental%40autistici.org.

Tallak Tveide

unread,
Sep 27, 2015, 12:31:34 PM9/27/15
to elixir-l...@googlegroups.com
Also, if the enumerable is a stream, this code wont always work (with the same argumentation)

Enum.take(size - Enum.count(enum))

Also you are iterating the list twice.

I am sorry for being a 'hardass' here, just trying to help :)



Sendt fra min telefon

> Den 26. sep. 2015 kl. 18.09 skrev eksperimental <eksper...@autistici.org>:
>
> --
> You received this message because you are subscribed to a topic in the Google Groups "elixir-lang-talk" group.
> To unsubscribe from this topic, visit https://groups.google.com/d/topic/elixir-lang-talk/pil9caRXQnM/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to elixir-lang-ta...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-talk/20150927000908.299bf8b7.eksperimental%40autistici.org.

Tallak Tveide

unread,
Sep 27, 2015, 12:43:59 PM9/27/15
to elixir-l...@googlegroups.com
Im thinking more along the lines of:

https://github.com/elixir-lang/elixir/blob/master/lib/elixir/lib/enum.ex#L2209

(Note docs at top of file)

And

https://github.com/elixir-lang/elixir/blob/master/lib/elixir/lib/stream.ex#L880

Seems there should be an enum.pad_zip and stream.pad_zip to be aligned with elixir std lib


Sendt fra min telefon

> Den 26. sep. 2015 kl. 18.09 skrev eksperimental <eksper...@autistici.org>:
>
> --
> You received this message because you are subscribed to a topic in the Google Groups "elixir-lang-talk" group.
> To unsubscribe from this topic, visit https://groups.google.com/d/topic/elixir-lang-talk/pil9caRXQnM/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to elixir-lang-ta...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-talk/20150927000908.299bf8b7.eksperimental%40autistici.org.
Reply all
Reply to author
Forward
0 new messages