192

I have an object (an "associate array" so to say - also known as a plain JavaScript object):

obj = {}
obj["Foo"] = "Bar"
obj["bar"] = "Foo"

I want to iterate over obj using CoffeeScript as follows:

# CS
for elem in obj

bu the CS code above compiles to JS:

// JS
for (i = 0, len = obj.length; i < len; i++)

which isn't appropriate in this case.


The JavaScript way would be for(var key in obj) but now I'm wondering: how can I do this in CoffeeScript?

Axel
  • 3,331
  • 11
  • 35
  • 58
jhchen
  • 14,355
  • 14
  • 63
  • 91
  • 4
    "Arrays" in JavaScript/CoffeeScript are special objects with numerical indices and a `length` property that simply refers to the highest numerical index (plus 1). What you want is just an "object": `obj = {}`. Arrays are objects, but there's no reason to use one in your example. – Trevor Burnham Jun 20 '11 at 15:15
  • 1
    Good point Trevor! I've modified the question to be a bit less misleading/confusing in this regard. – Per Lundberg Apr 28 '13 at 19:03

4 Answers4

354

Use for x,y of L. Relevant documentation.

ages = {}
ages["jim"] = 12
ages["john"] = 7

for k,v of ages
  console.log k + " is " + v

Outputs

jim is 12
john is 7

You may also want to consider the variant for own k,v of ages as mentioned by Aaron Dufour in the comments. This adds a check to exclude properties inherited from the prototype, which is probably not an issue in this example but may be if you are building on top of other stuff.

penmark
  • 37
  • 1
  • 5
Nick
  • 11,475
  • 1
  • 36
  • 47
  • 12
    Precisely. CoffeeScript's `of` compiles to JavaScript's `in`. It's a common point of confusion, but having `in` for use with arrays is incredibly useful. I talk about this at length in [the CoffeeScript book](http://pragprog.com/titles/tbcoffee/coffeescript). – Trevor Burnham Jun 20 '11 at 15:16
  • 3
    You should not initialise `arr` as `arr = []`, you should use `arr = {}`. In Javascript (and Coffeescript) arrays have numeric indices. Objects behave like associative arrays/dicts. – Morgan Harris Mar 18 '13 at 03:55
  • Thanks, that's been pointed out by Trevor and others already, and my answer was keeping to the original question code. I'll update my example to use a plain object for clarity anyway. – Nick Mar 18 '13 at 07:39
  • 13
    Although it doesn't matter for this particular example, it sounds like `for own key, value of obj` is closer to what OP is looking for. – Aaron Dufour Jun 14 '13 at 16:48
4

You're initializing an array, but then you're using it like an object (there is no "associative array" in js).

Use the syntax for iterating over objects (something like):

for key, val of arr
  console.log key + ': ' + val 
kioopi
  • 2,170
  • 2
  • 18
  • 26
  • 3
    Actually, *all* objects in JS are associative arrays (sans consistent key ordering). So the code jcmoney gave should work, though there's no reason to use `[]` instead of `{}` in that case. – Trevor Burnham Jun 20 '11 at 15:12
  • http://jashkenas.github.com/coffee-script/#loops looks like the loop generated by coffeescript will not iterate over object-members. – kioopi Jun 21 '11 at 15:19
3

The short hand version using array comprehension, which can be used as a one-line loop.

console.log index + ": " + elm for index, elm of array

Array comprehension are:

"Comprehensions replace (and compile into) for loops, with optional guard clauses and the value of the current array index. Unlike for loops, array comprehensions are expressions, and can be returned and assigned.", http://coffeescript.org/#loops

sqren
  • 22,833
  • 7
  • 52
  • 36
  • 5
    please explain. merely providing a code snippet isn't sufficient. stackoverflow is not a "gimme the codez" site, the idea is that others will benefit more if the answer provides a clarification of the abstract concept. – Eliran Malka Apr 29 '12 at 19:21
1

with your convention, arr is an array, but "foo" is a property of this array, it is not an indexed value. If you want to store your data the indexed values of an array, you should have written :

arr1 = []
arr1[0] = "Bar"
arr1[1] = "Foo"

or if you want an associative array, just use an object :

arr2 = {}
arr2["Foo"] = "Bar" // equivalent to arr2.foo="Bar"
arr2["bar"] = "Foo" // equivalent to arr2.bar="Foo"

if you want to loop over arr1 :

str = "values are : "
for val in arr2
  str += val + " |"
console.log key + ': ' + val

returns :

values are : Bar | Foo |

and to loop over arr2 : "for value in array"

for key, val of arr
  console.log key + ': ' + val

which returns :

Foo : Bar
Bar : Foo
Benibur
  • 816
  • 10
  • 9