0

如果我在 var 中有一个对象数组。我想减少这种情况,以便它们按特定属性分组。这是我的代码

array = tracks.reduce (x,y,i) ->
    x[y.album] = []
    x
, {}

albums = tracks.reduce (x,y,i) ->
    array[y.album].push {'name':y.name, 'mp3':y.mp3}
    array
, {}


console.log(albums)

它输出我想要的东西,但是我想知道是否有更好的方法来编写它,而不必执行第一个循环来为组创建空数组。

谢谢。

4

1 回答 1

4

是的,只有在没有初始化的情况下才可以使用or=or?=运算符进行赋值;array[y.ambum]因此只使用一个循环。顺便说一句,我认为array变量是一个对象有点令人困惑。另一种使用 CoffeeScript 循环而不是编码的方法reduce是:

albums = {}
for {album, name, mp3} in tracks
  (albums[album] or= []).push {name, mp3}

请注意,我正在使用解构来一次获取所有轨道属性。

或者,如果您想使用reduce

albums = tracks.reduce (albums, {album, name, mp3}) ->
  (albums[album] or= []).push {name, mp3}
  albums
, {}

但我认为 CS-loop 版本读起来更好:)

奖励曲目(双关语):如果您碰巧有 Underscore.js,我强烈建议您使用groupBy,这正是这种分组工作:

albums = _.groupBy tracks, (track) -> track.album

请注意,每个专辑名称的曲目albums将是“完整的”曲目(不仅仅是名称和 mp3 属性)。


更新:关于性能的评论:当被要求“有效地”做某事时,我将其解释为以最直接和最干净的方式做事(我在考虑程序员在阅读代码时的效率);但许多人会明确地将效率与绩效联系起来。

关于性能,这三个解决方案都是 O(n),n 是轨道数,复杂度;所以两者都没有比其他人差得可怕。

似乎原始for循环在现代 JS 引擎上的运行速度比其等效的高阶兄弟:forEach、、reduce等(这让 IMO 感到非常难过 :(...)。所以第一个版本应该比第二个版本运行得更快。

对于 Underscore 版本,我不会做任何预测,因为 Underscore以大量使用高阶函数而不是原始for循环而闻名,但同时,该版本不会为每个轨道创建一个新对象.

在任何情况下,在将解决方案更改为性能更高但可读性较差的解决方案之前,您都应该始终分析您的代码。如果您注意到该特定循环是一个瓶颈,并且您有一组很好的数据来对其进行基准测试,那么jsPerf会非常有用:)

于 2013-01-29T16:06:30.133 回答