16

How can one iterate over an ES6 Map or Set in Coffeescript?

In Javascript one would use e.g.

s = new Set()
s.add({a: 1})
for (x of s) {
  console.log(x);
}

However Coffeescript has its own of operator that gets converted to in, i.e.:

console.log(x) for x of s

becomes ... for (x in s) { ... }.

How can one access Javascript's of operator in Coffeescript?

One could write their own custom iterator by cycling over s.values().next(), but that'd be an abomination. :)

ProgramFOX
  • 6,131
  • 11
  • 45
  • 51
Brian M. Hunt
  • 81,008
  • 74
  • 230
  • 343

3 Answers3

9

There's currently no way to use the new Javascript ES6 of operator from coffeescript (as of 1.9.2). The best option for now is to use s.forEach (x) -> ... or m.forEach (value, key) -> as mentioned above.

For a set:

s = new Set
s.add {a: 1}

s.forEach (v) =>
  console.log v

For a map:

m = new Map
m.set {a: 1}, {b: 2}

m.forEach (v, k) =>
  console.log k, v

If you want to avoid creating new functions for whatever reason, you can use iterators directly from coffeescript. But its a little bit nasty. For sets:

i = s.values()
while(v = i.next(); !v.done)
  console.log v.value

For a map:

i = m.entries()
while(v = i.next(); !v.done)
  [key, value] = v.value
  console.log key, value

The parentheses on the while loop are necessary to make the while loop dependant on v.done.

They can be done on one line too - but it looks pretty bad:

i = s.values(); console.log v.value while(v = i.next(); !v.done)
Joseph
  • 1,172
  • 1
  • 10
  • 12
  • 1
    In the first line, did you mean to say "the new JavaScript ES6 **`of`** operator"? –  Apr 23 '15 at 04:50
  • 1
    Notice that `of` uses iterators in a little different way. It has an implicit `try finally` wrapped around that calls `i.return()` should the loop body return prematurely. – Bergi Apr 23 '15 at 09:02
  • Yeah - fixed the reference to the `of` operator (thanks!). And fascinating, @Bergi – Joseph Apr 24 '15 at 09:52
  • This is no longer correct. Could you please edit to add a note re. Coffeescript 2.0? http://coffeescript.org/announcing-coffeescript-2/ – Brian M. Hunt Oct 23 '17 at 12:45
5

Coffeescript 2.0for …from

JavaScript’s for…of is now available as CoffeeScript’s for …from (we already had a for …of): for n from generatorFunction()

Coffeescript 1.0 — Backticks

One option is to use the backtick to embed raw Javascript i.e. http://coffeescript.org/#embedded.

`for (x of y) { }`
Brian M. Hunt
  • 81,008
  • 74
  • 230
  • 343
1

You want to do something like this:

eat food for food in ['toast', 'cheese', 'wine']

(where eat is a function)

In your case, you would do:

console.log(x) for x in s

Ref: http://coffeescript.org/#loops

It's helpful to use the coffeescript REPL. You can open it by typing coffee in your console. Try the following code:

_ = require 'underscore' #substitute underscore for lodash, if you prefer
s = ["a", "b", "c"]
console.log(x) for x in s

Edit:

Unfortunately, the Set functionality from ES6 doesn't seem to have made it into Coffeescript yet. Consider using underscore the lodash methods _.unique() or _.union() to mimic the functionality you're looking for.

For the example above:

s = _.unique ["a", "a", "b", "b", "b", "c"]
console.log(x) for x in s
Ashwin Balamohan
  • 3,303
  • 2
  • 25
  • 47
  • I think you have misread the question. What needs to work, using your example, would be `eat food for food in new Set(['toast', 'cheese', 'wine'])`, which fails because CoffeeScript converts that to a `for` loop. ES6 Sets have neither a `length` property nor indexes. – Brian M. Hunt Jan 20 '15 at 02:53
  • I did in fact misread it. Thanks for the clarification. It doesn't look like sets have made it into Coffeescript yet. You may be able to use underscore or lodash to get around this, though. See my edit, above – Ashwin Balamohan Jan 20 '15 at 15:24
  • Thanks @Ashwin -- another option is in the comments to the question (`s.forEach (x) -> ...`). I will post if I see anything that illuminates further. – Brian M. Hunt Jan 20 '15 at 16:44
  • No problem at all. `s.forEach()` works well if you're working with pure JS, but the `s = new Set()` line will throw a ReferenceError in Coffeescript. – Ashwin Balamohan Jan 20 '15 at 20:15