Rob Fletcher
Rob Fletcher

Reputation: 8627

Is there an idiomatic way to test array equality in Coffeescript?

The expression

[1, 2, 3] == [1, 2, 3]

evaluates to false in Coffeescript but is there a concise, idiomatic way to test array equality?

Upvotes: 23

Views: 4944

Answers (6)

Lars Gyrup Brink Nielsen
Lars Gyrup Brink Nielsen

Reputation: 4105

This function returns true if arrays have same length and all values with same index have same value. It throws an error if either argument isn't an array.

isArray = Array.isArray || (subject) ->
    toString.call(subject) is '[object Array]'

compareArrays = (a, b) ->
    unless isArray(a) and isArray b
        throw new Error '`arraysAreEqual` called with non-array'

    return false if a.length isnt b.length

    for valueInA, index in a
        return false if b[index] isnt valueInA

    true

Upvotes: 0

user3118605
user3118605

Reputation: 41

The following works great and requires no dependencies:

arrayEqual = (ar1, ar2) ->
  JSON.stringify(ar1) is JSON.stringify(ar2)

Upvotes: 3

Evan Hahn
Evan Hahn

Reputation: 12722

I'm a big fan of Sugar.js. If you happen to be using that:

a = [1, 2, 3]
b = [1, 2, 3]
Object.equal(a, b)

Upvotes: 0

obmarg
obmarg

Reputation: 9569

If you don't mind introducing an Underscore.js dependency you could use some of it's utilities. It's not massively elegant, but I can't think of an easier way to do it with plain coffeescript:

a = [ 1, 2, 3 ]
b = [ 1, 2, 3 ]
equal = a.length == b.length and _.all( _.zip( a, b ), ([x,y]) -> x is y )

Upvotes: 6

epidemian
epidemian

Reputation: 19229

If you are dealing with arrays of numbers, and you know that there are no nulls or undefined values in your arrays, you can compare them as strings:

a = [1, 2, 3]
b = [1, 2, 3]

console.log "#{a}" is "#{b}" # true
console.log '' + a is '' + b # true

Notice, however, that this will break as soon as you start comparing arrays of other things that are not numbers:

a = [1, 2, 3]
b = ['1,2', 3]

console.log "#{a}" is "#{b}" # true

If you want a more robust solution, you can use Array#every:

arrayEqual = (a, b) ->
  a.length is b.length and a.every (elem, i) -> elem is b[i]

console.log arrayEqual [1, 2, 3], [1, 2, 3]   # true
console.log arrayEqual [1, 2, 3], [1, 2, '3'] # false
console.log arrayEqual [1, 2, 3], ['1,2', 3]  # false

Notice that it's first comparing the lengths of the arrays so that arrayEqual [1], [1, 2, 3] doesn't return true.

Upvotes: 15

Hector Correa
Hector Correa

Reputation: 26690

I wouldn't consider this idiomatic but this would be a way of doing it without adding an extra library:

a = [1, 2, 3, 4]
b = [22, 3, 4]

areEqual = true
maxIndex = Math.max(a.length, b.length)-1
for i in [0..maxIndex]
    testEqual = a[i] is b[i]
    areEqual = areEqual and testEqual

console.log areEqual

A cleaner approach would be using JavaScript's reduce() function. This is a bit shorter but I am not sure all browsers support reduce.

a = [1, 3, 4, 5]
b = [1, 3, 4, 5]

maxIndex = Math.max(a.length, b.length)-1
areEqual = true
[0..maxIndex].reduce (p, c, i, ar) -> areEqual = areEqual and (a[i] is b[i])

console.log "areEqual=#{areEqual}"

Upvotes: 3

Related Questions