Enum.index/2

59 views
Skip to first unread message

José Valim

unread,
Dec 8, 2020, 3:05:10 PM12/8/20
to elixir-l...@googlegroups.com
I would like to propose an Enum.index/2 function. It behaves like with_index/2 but the index is the first argument:

    iex> Enum.index([:a, :b, :c])
    [{0, :a}, {1, :b}, {2, :c}]

I am hoping it reads "index" this tuple (hence the index as the first element. While with_index means attach an index information to each element (hence the second element). Is this sound?

Thank you,

Felipe Stival

unread,
Dec 8, 2020, 3:11:03 PM12/8/20
to elixir-l...@googlegroups.com
I'm not sure. Sounds a bit ambiguous, couldn't this be an option for a new Enum.with_index/3?

--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4K6h7c1UbiEfoEsyCXGJRbO8he%3DFJ84yxC%2B3-GOo-2MwQ%40mail.gmail.com.


--
logo
Felipe Stival, Electrical Engineering Student 
Santa Maria, Rio Grande do Sul
Brasil
FacebookTwitterLinkedInGithub

José Valim

unread,
Dec 8, 2020, 3:14:13 PM12/8/20
to elixir-l...@googlegroups.com
I considered the option but I prefer to avoid using options that change the return type.

Felipe Stival

unread,
Dec 8, 2020, 3:39:11 PM12/8/20
to elixir-l...@googlegroups.com
That's a really good point.
Maybe `indexed`? `with_index` sounds like perfect past for me, so this would be similar. Still `index` is fine.

About the function itself, I find it useful and believe it should be on Enum.

Andrew Fontaine

unread,
Dec 8, 2020, 3:43:07 PM12/8/20
to elixir-l...@googlegroups.com
I'm not sure I see the benefit of the new Enum.index/2 over
Enum.with_index/2 and Enum.map/2.

That is to say, why would the language need both? I will admit it makes
piping into Enum.into/2 potentially nicer.

Greg Vaughn

unread,
Dec 8, 2020, 3:44:45 PM12/8/20
to elixir-l...@googlegroups.com
If this is related to the mystery benchmark tweets, José, then I guess I'm in favor of the proposal :-)

I do prefer Felipe's name of `Enum.indexed/1` though. While `index` can be a verb, it's ambiguous with the noun. `indexed` is clearly a past tense verb.

-Greg Vaughn

> On Dec 8, 2020, at 2:13 PM, José Valim <jose....@dashbit.co> wrote:
>
> I considered the option but I prefer to avoid using options that change the return type.
>
> On Tue, Dec 8, 2020 at 9:11 PM Felipe Stival <v0i...@gmail.com> wrote:
> I'm not sure. Sounds a bit ambiguous, couldn't this be an option for a new Enum.with_index/3?
>
> Em ter., 8 de dez. de 2020 às 17:05, José Valim <jose....@dashbit.co> escreveu:
> I would like to propose an Enum.index/2 function. It behaves like with_index/2 but the index is the first argument:
>
> iex> Enum.index([:a, :b, :c])
> [{0, :a}, {1, :b}, {2, :c}]
>
> I am hoping it reads "index" this tuple (hence the index as the first element. While with_index means attach an index information to each element (hence the second element). Is this sound?
>
> Thank you,
>
>
> --
> You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4K6h7c1UbiEfoEsyCXGJRbO8he%3DFJ84yxC%2B3-GOo-2MwQ%40mail.gmail.com.
>
>
> --
>
> Felipe Stival, Electrical Engineering Student
> Santa Maria, Rio Grande do Sul
> Brasil
> v0idpwn.github.io
>
>
> --
> You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/CAKC64%2Bx4zERK_axkS2puMT9Qa8dJKYEh_Z3QNDf977eJG0-6aw%40mail.gmail.com.
>
> --
> You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4Kj%3DS54yn-1jmoaG%2BKEab9ZLpagHYDfpNEu%2BSbtTdj%2B4g%40mail.gmail.com.

Kelvin Raffael Stinghen

unread,
Dec 8, 2020, 3:52:04 PM12/8/20
to elixir-lang-core
I can't see why not just `x |> Stream.with_index() |> Stream.map(fn {v, i} -> {i, v} end)`... I mean, lots of proposals for similar functions got denied because it would be easy to develop a lib that does it cause Elixir is awesomely extensible, so why bothering add another variant? Do you have to do that too many times on Elixir core or something like that?

José Valim

unread,
Dec 8, 2020, 4:10:10 PM12/8/20
to elixir-l...@googlegroups.com
The main reason for an index function is to make it easier to build a map:

    Map.new Enum.index(data)

I agree the duplicity between noun and verb is undesirable though.

Austin Ziegler

unread,
Dec 8, 2020, 4:35:46 PM12/8/20
to elixir-l...@googlegroups.com
I’m not opposed to the idea, but wouldn’t that map be easily done with:

    Map.new(Enum.with_index(data), fn {v, k} -> {k, v} end)

The biggest advantage of Map.new(Enum.index(data)) is that the number of tuple creations is halved.

-a



--

Zach Daniel

unread,
Dec 8, 2020, 4:46:09 PM12/8/20
to elixir-l...@googlegroups.com
I commonly need to flip the keys/values when using Map.new, why not add an option to Map.new? I don’t like this name, but this reads pretty nicely to me

list
|> Enum.with_index()
|> Map.new(flip: true)

Paul Clegg

unread,
Dec 8, 2020, 4:50:33 PM12/8/20
to elixir-l...@googlegroups.com
FWIW, I like the "indexed" function name; I think the past tense of the verb helps indicate what it returns.  The ambiguous nature of the verb/noun "index" in English makes for confusion, for sure.  "What does Enum.indexed do?"  "It returns the Enum, indexed."  "Ah."

...Paul



Bruce Tate

unread,
Dec 8, 2020, 4:50:53 PM12/8/20
to elixir-l...@googlegroups.com
Maybe a transform function on with_index? 

Enum.with_index([:a, :b, :c], &{&2, &1})


-bt

--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4K6h7c1UbiEfoEsyCXGJRbO8he%3DFJ84yxC%2B3-GOo-2MwQ%40mail.gmail.com.


--

Regards,
Bruce Tate
CEO

Zach Daniel

unread,
Dec 8, 2020, 4:57:47 PM12/8/20
to elixir-l...@googlegroups.com
I like that idea a lot Bruce. Let’s you do something like:

maps |> Enum.with_index(&Map.put(&1, :index, &2))

Bruce Tate

unread,
Dec 8, 2020, 5:02:13 PM12/8/20
to elixir-l...@googlegroups.com
There is a bit of a collision with the option for the offset, but you could pattern match that. 

-bt

Christopher Keele

unread,
Dec 8, 2020, 6:51:12 PM12/8/20
to elixir-lang-core
I think that even if it enabled awesome optimization opportunities,
1. Having both Enum.index_with and Enum.index/indexed will confuse people.
2. Straying from Elixir's consistent API design of "Module X functions take X's as their first argument" will confuse people.
  a. Especially in the very consistent and large-surface-area Enum module.

Both together seem like a less-than-ideal combination. These trade-offs may be worth it depending on what is gained, though.

I hadn't seen the second point mentioned yet in this thread yet. Which makes me wonder if there is a different module it might belong under, instead, resolving both problems while preserving the intention-revealing index function name?

ie:  Integer.index(start \\ 0 :: non_neg_integer, Enum.t) :: Enum.t
Kind of communicates that we are indexing an enumerable by an integer value; and just appears a little non-standard when we omit the starting point.

Creating a new module namespace for such a function to live--ex Index--seems a little excessive in this case, a costly increase in the surface of the standard library. (Is Enum.Index.by/2 unreasonable? Probably.)
Worth nothing that these sorts of one-off-function discussions are exactly how some modules we have today came into being, though--Atom and Tuple come to mind. But "indexes" are hardly first-class language concepts.

Adam Lancaster

unread,
Dec 8, 2020, 7:29:54 PM12/8/20
to elixir-l...@googlegroups.com
You could also use the new zip_with:

Map.new(Enum.zip_with(list, 0..length(list), & {&2, &1}))

Anil Kulkarni

unread,
Dec 8, 2020, 7:48:08 PM12/8/20
to elixir-l...@googlegroups.com

If there was no Enum.with_index/2 function in existence today, how would we implement it? My personal preference is to do {index, value}, as per José’s message.

If we are to make a change, I would prefer to create some new API (for back-compat), and then deprecate/remove Enum.with_index().

 

However, it’s my opinion that this is too much churn for something that is easily accomplished with `Enum.map()`, and I would just leave it as-is, chalked up to legacy decisions.

 

-Anil

 

Regards,

Bruce Tate

CEO



Image removed by sender.

--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/CAFXvW-4QOLzA4h34KBVSF1OnMFzxJZEwReV334YP3Pwu7cYX1g%40mail.gmail.com.

--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.

 

Regards,

Bruce Tate

CEO



Image removed by sender.

--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/8cfe7aca-a579-405e-89a7-3f81774af255n%40googlegroups.com.

--

You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.

José Valim

unread,
Dec 9, 2020, 1:07:31 AM12/9/20
to elixir-l...@googlegroups.com
I like Bruce's option a lot and I will proceed with that. Thanks Bruce and everyone!

José Valim

unread,
Dec 9, 2020, 3:16:10 AM12/9/20
to elixir-l...@googlegroups.com

PR is welcome!

Thanks.

Valter Sundström

unread,
Dec 9, 2020, 5:43:35 AM12/9/20
to elixir-l...@googlegroups.com
I know I'm late to the party, but I personally feel weird about this choice. Overloading an argument to be either offset or a function is confusing and unnecessarily inconsistent in my opinion.
Personally, with this implementation, I would prefer an explicit name, like Enum.map_with_index, since now this feels a lot more like a mapping function than one for adding indices.
Secondly, I feel the original intent has gotten lost in a way? If this is being done in the name of efficiency, isn't it a lot worse to be calling a function, rather than just generating tuples?
If the expected use-case is to be thrown into Map.new, I feel, again, it might be better to add a specific function like Map.indexed_new or similar.

Just my 2 quarters of a cent. // Valter

Reply all
Reply to author
Forward
0 new messages