for statement with index and value

# Tingan Ho (9 years ago)

Just following a discussion we had on TypeScript Microsoft/TypeScript#3835

In most times, I just need the value in an array, so I use a for..of loop. But then, I find out that I need the index too, then I need to rewrite my whole for loop expression. Happens all the time for me.

I have to ask why there doesn't exist a for statement where I can get the index and value of an array directly? Or for that matter property and value of an object?

.forEach is not ideal since you can't break, break to outer loop and continue cleanly. Even though you can achieve this with other array methods, I don't think they are as productive as a for-statement.

What I'm suggesting is augmenting the current syntax for for..of loops. And support an overloading pattern so that we don't need to rewrite the whole for loop expression to just to get the index when we already getting the value.

// overloads
for (let value, index of values) { ... }
for (let value of values) { ... }

PS. Sorry if this has already discussed. Couldn't find any on Google and the esdiscuss.org page doesn't have any search capabilities.

# Kevin Smith (9 years ago)

Destructuring is here to help:

for (let [index, value] of [1, 2, 3].entries())
    console.log(index + ": " + value)

The "entries" method returns an iterator of [index, value] pairs.

# Tingan Ho (9 years ago)

for (let [index, value] of [1, 2, 3].entries()) console.log(index + ": " + value)

I still think most people will write:

for (let value of values) { ... }

and then rewrite the whole expression inside the for-loop when they find out that they need the index too:

for (let [index, value] of [1, 2, 3].entries())
        console.log(index + ": " + value)

for (let value, index of values) { ... } is still much easier to type than for (let [index, value] of [1, 2, 3].entries()) and also more readable.

Also, doesn't that makes a copy of the [1, 2, 3]?

# Logan Smyth (9 years ago)

Unfortunately we can't have both

for (let value of values){

and

for (let [index, value] of values){

Over all, the first one is the more likely one on a day-to-day basis.

The [] are needed because the for...of follows the standard rules for assignment, so it uses standard destructuring, and JS array destructuring requires [].

for (let [index, value] of values.entries()){

is essentially is the same as

for (let pair of values.entries()){
    let [index, value] = pair;

As for your last question, .entries returns an iterator, so it will not create a copy of the array.

# Tingan Ho (9 years ago)

Unfortunately we can't have both...

for (let [index, value] of values){

I was suggesting the syntax:

for (let value, index of values){

value comes first and no [ ... ].

# Edwin Reynoso (9 years ago)

So I'm assuming this would be special to arrays??

because destructuring works fine for anything that's iterable:

meaning how would it know what to take out for Sets??

for(let value, index of [1,2]) {
 // do something
}

With destructuring we at least know what's being extracted (not sure if destructured would be the right word, clueless on that):

let it = [1,2].entries();
let [index, value] = it.next();
// same as:
let [index, value] = [0, 1];
// the matching is obvious

With your suggestion it's not obvious:

for(let value, index of [1,2]) // how does it know what value and index
would be??

I don't think this would be done if it's only for Arrays.

# Edwin Reynoso (9 years ago)

Something wrong with server that doesn't let me edit.

But what I meant by the first code snippet was:

for(let a, b of new Set([1,2])) // what would `a` and `b` be here? How
would it know what to extract??

Would b just be undefined, yet for an array it returns the index how does it determine that unless again this is special to Arrays?? because b/index could be anything else, that's not obvious compare to destructuring.

# Tingan Ho (9 years ago)

Yes the proposed syntax is a special case for arrays.

tis 14 juli 2015 kl 12:23 skrev Edwin Reynoso <eorroe at gmail.com>:

# aakarsh1997 (9 years ago)

Do we have anything similar for iterating objects with property names as well? (as asked in the original post as well)

# Jorge Bucaran (9 years ago)

Unless you have a specific requirement I am missing, your use case is more elegantly resolved IMO using a custom generator that yields exactly the information you need per iteration.

A functional approach using a function that has the information you need is also another valid solution.

<div>-------- 元のメール --------</div><div>送信元: Tingan Ho <tingan87 at gmail.com> </div><div>日時:2015/07/14 PM1:32 (GMT+09:00) </div><div>宛先: Edwin Reynoso <eorroe at gmail.com> </div><div>Cc: es-discuss <es-discuss at mozilla.org> </div><div>件名: Re: for statement with index and value </div><div> </div>Yes the proposed syntax is a special case for arrays.

tis 14 juli 2015 kl 12:23 skrev Edwin Reynoso <eorroe at gmail.com>:

Something wrong with server that doesn't let me edit.

But what I meant by the first code snippet was:

for(let a, b of new Set([1,2])) // what would `a` and `b` be here? How would it know what to extract??

Would b just be undefined, yet for an array it returns the index how does it determine that unless again this is special to Arrays?? because b/index could be anything else, that's not obvious compare to destructuring.

On Tue, Jul 14, 2015 at 12:13 AM, Edwin Reynoso <eorroe at gmail.com> wrote:

So I'm assuming this would be special to arrays??

because destructuring works fine for anything that's iterable:

meaning how would it know what to take out for Sets??

for(let value, index of [1,2]) {
 // do something
}

With destructuring we at least know what's being extracted (not sure if destructured would be the right word, clueless on that):

let it = [1,2].entries();
let [index, value] = it.next();
// same as:
let [index, value] = [0, 1];
// the matching is obvious

With your suggestion it's not obvious:

for(let value, index of [1,2]) // how does it know what value and index would be??

I don't think this would be done if it's only for Arrays.

On Tue, Jul 14, 2015 at 12:04 AM, Tingan Ho <tingan87 at gmail.com> wrote:

Unfortunately we can't have both...

for (let [index, value] of values){

I was suggesting the syntax:

for (let value, index of values){

value comes first and no [ ... ].

On Tue, Jul 14, 2015 at 11:52 AM, Logan Smyth <loganfsmyth at gmail.com> wrote:

Unfortunately we can't have both

for (let value of values){

and

for (let [index, value] of values){

Over all, the first one is the more likely one on a day-to-day basis.

The [] are needed because the for...of follows the standard rules for assignment, so it uses standard destructuring, and JS array destructuring requires [].

for (let [index, value] of values.entries()){

is essentially is the same as

for (let pair of values.entries()){
    let [index, value] = pair;

As for your last question, .entries returns an iterator, so it will not create a copy of the array.

On Mon, Jul 13, 2015 at 7:43 PM, Tingan Ho <tingan87 at gmail.com> wrote:

for (let [index, value] of [1, 2, 3].entries()) console.log(index + ": " + value)

I still think most people will write:

for (let value of values) { ... }

and then rewrite the whole expression inside the for-loop when they find out that they need the index too:

for (let [index, value] of [1, 2, 3].entries()) 
        console.log(index + ": " + value)

for (let value, index of values) { ... } is still much easier to type than for (let [index, value] of [1, 2, 3].entries()) and also more readable.

Also, doesn't that makes a copy of the [1, 2, 3]?

# Jonathan Bond-Caron (9 years ago)

On Mon Jul 13 10:22 PM, Kevin Smith wrote:

Destructuring is here to help:

for (let [index, value] of [1, 2, 3].entries()) 
    console.log(index + ": " + value)

The "entries" method returns an iterator of [index, value] pairs.

Can't there be a 'key iterator' syntax?

for (let value, index of [1, 2, 3]) console.log(index + ": " + value)

let value = itOfValues.next().value; let index= itOfKeys.next().value;

  • An array has an implicit 'key iterator' cause there's a key for each value.
  • Everything else has a 'keyIteratorFrom0ToInifinity'

So you have a 'value iterator' and a 'key iterator' for each thing on the RHS. Doesn't seem like much of an issue, engines just need a keyIteratorFrom0ToInifinity for non-array things cases.

# Matthew Robb (9 years ago)

Why not use the new meta syntax?

for (let value of values) { console.log(for.index); }

  • Matthew Robb
# Domenic Denicola (9 years ago)

From: es-discuss [mailto:es-discuss-bounces at mozilla.org] On Behalf Of Matthew Robb

Why not use the new meta syntax?

This is pretty ingenious. If I thought this was a real problem that needed solving, I'd definitely go this route. (But, I think that using .entries() and destructuring is fine, and there's no need to add new syntax to save people a few characters.)

# Jonathan Bond-Caron (9 years ago)

On Tue Jul 14 09:27 AM, Domenic Denicola wrote:

From: es-discuss [mailto:es-discuss-bounces at mozilla.org] On Behalf Of Matthew Robb

Why not use the new meta syntax?

If I thought this was a real problem that needed solving,

Disagree

"As early as the mid-1980’s, it was observed that programming language research and funding emphasized technical aspects of the domain and neglected psychological aspects:"

" The human and computer parts of programming languages have developed in radical asymmetry"

repository.cmu.edu/cgi/viewcontent.cgi?article=1805&context=isr

Bias of Engineering problems > Psychology

# Andreas Rossberg (9 years ago)

On 14 July 2015 at 15:41, Jonathan Bond-Caron <jbondc at gdesolutions.com>

wrote:

On Tue Jul 14 09:27 AM, Domenic Denicola wrote:

From: es-discuss [mailto:es-discuss-bounces at mozilla.org] On Behalf Of Matthew Robb

Why not use the new meta syntax?

If I thought this was a real problem that needed solving,

Disagree

"As early as the mid-1980’s, it was observed that programming language research and funding emphasized technical aspects of the domain and neglected psychological aspects:"

" The human and computer parts of programming languages have developed in radical asymmetry"

repository.cmu.edu/cgi/viewcontent.cgi?article=1805&context=isr

Bias of Engineering problems > Psychology

You might want to catch up on the recent discussion we just had here:

esdiscuss/2015-June/043307

Complexity is very much a "psychological" aspect. And random special cases, syntactic additions, and irregularities eat into the complexity budget quickly.

# Tingan Ho (9 years ago)

This is pretty ingenious. If I thought this was a real problem that needed

solving

I'm not sure how I should interpret this. But I'm pretty sure you also need the current index of array in a for loop.

Since I can access the index and value directly in .forEach(value, index, array), why isn't there a for-loop-statement/control-flow-statement for doing the same thing?

And yes I heard it can be solved with different methods. We can go on discuss different way to loop through an array, recursive functions, while-loops, iterators, generators, meta syntax etc. But they aren't clean solutions to a wildly popular problem.

All these counter arguments. Can you explain why even .forEach(value, index, array) made the deal also?

tis 14 juli 2015 kl 21:41 skrev Jonathan Bond-Caron <jbondc at gdesolutions.com

# Domenic Denicola (9 years ago)

From: Tingan Ho [mailto:tingan87 at gmail.com]

But they aren't clean solutions to a wildly popular problem.

I disagree.

# Alexander Jones (9 years ago)

It's called enumerate in Python. And it's trivial to implement:

for (let [i, value] of enumerate(someIterable)) {
   // behold...
}
# Sébastien Doeraene (9 years ago)

And it's called zipWithIndex in Scala:

for ((value, i) <- someTraversable.zipWithIndex) {
  // do stuff
}

And, in Ruby, it's each_with_index:

for value, i in someArray.each_with_index
  # do stuff
end

I see a pattern, here. It seems several other languages are pretty fine with a simple method that bundles elements of a collection with their indices, and then rely on destructuring on the left-hand-side of their for loop to extract them again, instead of adding additional syntax for this use case. IMO, that's a strong argument for doing the same thing in ES.

Cheers, Sébastien

I think there's something

# Tab Atkins Jr. (9 years ago)

On Mon, Jul 13, 2015 at 7:13 PM, Tingan Ho <tingan87 at gmail.com> wrote:

Just following a discussion we had on TypeScript Microsoft/TypeScript#3835

In most times, I just need the value in an array, so I use a for..of loop. But then, I find out that I need the index too, then I need to rewrite my whole for loop expression. Happens all the time for me.

I have to ask why there doesn't exist a for statement where I can get the index and value of an array directly? Or for that matter property and value of an object?

.forEach is not ideal since you can't break, break to outer loop and continue cleanly. Even though you can achieve this with other array methods, I don't think they are as productive as a for-statement.

What I'm suggesting is augmenting the current syntax for for..of loops. And support an overloading pattern so that we don't need to rewrite the whole for loop expression to just to get the index when we already getting the value.

// overloads
for (let value, index of values) { ... }
for (let value of values) { ... }

PS. Sorry if this has already discussed. Couldn't find any on Google and the esdiscuss.org page doesn't have any search capabilities.

Kevin provided the built-in answer for arrays, but for arbitrary iterables, the Python solution is trivial:

function* enumerate(iter) { let i = 0; for(let value of iter) { yield [i, value]; i++ } }

for(let [i, v] of enumerate(values)) { ... }

I expect there's already libraries that duplicate all of Python's itertools and more; the iterator algebra is really trivially hackable.

# Rick Waldron (9 years ago)

If you need the index of a value in an array, there is always... "indexOf" ;)

for (let value of values) { let index = values.indexOf(value); }

# Tingan Ho (9 years ago)

Thanks for all the suggestion. I think since not many languages supports this it would be very hard to convince you.

I think I can live with the for (let [index, value] of arr.entries()) {} solution.

One

ons 15 juli 2015 kl 09:02 skrev Rick Waldron <waldron.rick at gmail.com>:

# Sebastian Zartner (9 years ago)

That only works if all values are distinct. The following will result in the wrong index for the last item:

let values = ["a", "b", "a"];

for (let value of values) { let index = values.indexOf(value); }

Also that construct is not very performant.

Sebastian

# Jonathan Bond-Caron (9 years ago)

On Tue Jul 14 10:43 AM, Andreas Rossberg wrote:

esdiscuss/2015-June/043307, esdiscuss/2015-June/043307

Complexity is very much a "psychological" aspect. And random special cases, syntactic additions, and irregularities eat into the complexity budget quickly.

Fair enough, agree with that.

Seems like it would be a Googly thing to objectively measure language "complexity" or "simplicity"? The complexity rank algorithm?

Dismissing these things as "not real problems" is more history repeating itself. Love the JS conservatism & Smalltalkness, less the coin tosses about perceived complexity, science wins there.

# Rick Waldron (9 years ago)

On Wed, Jul 15, 2015 at 2:21 AM Sebastian Zartner < sebastianzartner at gmail.com> wrote:

That only works if all values are distinct. The following will result in the wrong index for the last item:

Indeed, but useful if the program can reliably know that the array will contain only unique entries.