用于对数组的等效元素进行分组的函数

时间:2013-07-06 23:56:37

标签: javascript coffeescript underscore.js

是否有 javascript coffeescript 功能(或者可能是下划线 groupBy 功能的扩展名)接收数组等价比较器(具有两个参数的布尔函数,而不仅仅是一个参数)和基于的数组元素这个等价比较器?

作为我想要的一个例子:

areEquivalent = (p1, p2) ->
  p1.birthYear == p2.birthYear and
  p1.birthPlace == p2.birthPlace and
  p1.gender == p2.gender

p1 = {name:'Anna', birthYear: 1990, birthPlace: 'Alaska', gender: 'female', hasCar: true, hasChildren: false}
p2 = {name:'John', birthYear: 1990, birthPlace: 'Alaska', gender: 'male', hasCar: true, hasChildren: false}
p3 = {name:'Dora', birthYear: 1980, birthPlace: 'Hawaii', gender: 'female', hasCar: true, hasChildren: true}
p4 = {name:'Lumi', birthYear: 1980, birthPlace: 'Hawaii', gender: 'female', hasCar: false, hasChildren: false}
p5 = {name:'Jack', birthYear: 1990, birthPlace: 'Alaska', gender: 'male', hasCar: false, hasChildren: false}

console.log areEquivalent p1, p2
# false
console.log areEquivalent p3, p4
# true

people = [p1, p2, p3, p4, p5]

console.log _.groupEquivalentObjects(people, areEquivalent)
# [ [p1], [p2,p5], [p3,p4] ]

2 个答案:

答案 0 :(得分:4)

你能不能只传递_.groupBy()和表达式来正确区分你的输入?

p1 = {name:'Anna', birthYear: 1990, birthPlace: 'Alaska', gender: 'female', hasCar: true, hasChildren: false}
p2 = {name:'John', birthYear: 1990, birthPlace: 'Alaska', gender: 'male', hasCar: true, hasChildren: false}
p3 = {name:'Dora', birthYear: 1980, birthPlace: 'Hawaii', gender: 'female', hasCar: true, hasChildren: true}
p4 = {name:'Lumi', birthYear: 1980, birthPlace: 'Hawaii', gender: 'female', hasCar: false, hasChildren: false}
p5 = {name:'Jack', birthYear: 1990, birthPlace: 'Alaska', gender: 'male', hasCar: false, hasChildren: false}

people = [p1, p2, p3, p4, p5]

groups = _.groupBy(people, (x) -> '' + x.birthYear + x.birthPlace + x.gender)

console.log groups

http://jsfiddle.net/vKz6r/

答案 1 :(得分:0)

谢谢大家的答案和建议。

目前我实施了这个不是非常理想的解决方案:

# Modifies the received array, by removing all the elements equivalent to the first one,
# and returning them in a separate array
extractAllObjectsEquivalentToFirst = (array, areEquivalent) ->
  return [] if array.length == 0
  first = array.shift()
  equivalent = [first]
  different = []
  while array.length > 0
    elem = array.shift()
    if areEquivalent(elem,first)
      equivalent.push elem
    else
      different.push elem
  array[..] = different
  return equivalent

groupEquivalentObjects = (array, areEquivalent) ->
  arrayClone = array[..]
  groups = []
  previous = arrayClone.length
  while arrayClone.length > 0
    groups.push extractAllObjectsEquivalentToFirst(arrayClone, areEquivalent)
    if arrayClone.length >= previous
      console.warn "Array length did not decrease!"
      arrayClone = []
    previous = arrayClone.length
  return groups

但确实更好的解决方案是为项目定义某种 hashCode()函数,并将该函数作为参数传递给 _。 GROUPBY()

在我目前的用例中,我需要比较的一些对象属性实际上是数组,我需要使用 _。isEqual( )等效比较器内的

目前我懒得想办法定义一个“hashCode”函数,以确保我的用例值的明确等价。