Add forEachWithIndex to Array

Often, when enumerating a collection without a need to map or filter, I'll reach for forEach. However this doesn't work when I'm interested in seeing the index of a particular element, requiring me to drop down to the slightly less terse, and much less Swifty:

for (ix, element) in foo.enumerated(){
  doStuff(ix, element)
}

when what I really want is:

foo.forEachWithIndex(doStuff)

The following extension allows this, and seems to be a simple, non-breaking change to the standard library, if accepted:

extension Array{

  func forEachWithIndex(_ callback: (Int, Element) -> ()){

	  for (index, element) in self.enumerated(){
		callback(index, element)
	  }
    }
}

Thanks for reading!

Don't think there's a need to extend the name that much, func forEach(_ body: (Int, Self.Element) throws -> Void) rethrows in pair with the non-enumerated forEach is just fine.

P.S. It would be Sequence we are adding to.

foo.enumerated().forEach is 90% of that without adding a new function (you have to unpack the elements inside the closure). How often does this come up in practice?

4 Likes

Instead of foo.enumerated() you might want to use:

  1. zip(0..., foo) or
  2. zip(foo.indices, foo)

See also:

1 Like

It's also worth noting that often when you need to iterate over indices (rather than just elements) its because you plan on mutating the array using that index. But a higher-level function like this will be holding a copy of the collection while looping, which means for value types a full copy will be triggered on first mutation. The more layers of abstraction/convenience in an operation like this, the more likely the user will miss this issue (which is easily missed, I did just the other day).

4 Likes