如果我在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)
它输出我想要的东西,但是我想知道是否有更好的方法来编写它,而不必进行第一次循环,为组创建空数组。
感谢。
答案 0 :(得分:4)
是的,您可以使用or=
或?=
运算符仅在尚未初始化时指定array[y.ambum]
;因此只使用一个循环。顺便说一下,我认为array
变量是一个对象有点令人困惑。使用CoffeeScript循环而不是reduce
对此进行编码的另一种方法是:
albums = {}
for {album, name, mp3} in tracks
(albums[album] or= []).push {name, mp3}
请注意,我正在使用destructuring一次获取曲目属性。
或者,如果您想使用reduce
:
albums = tracks.reduce (albums, {album, name, mp3}) ->
(albums[album] or= []).push {name, mp3}
albums
, {}
但我认为CS循环版本读得更好一些:)
奖金跟踪(双关语):如果您碰巧拥有Underscore.js,我强烈建议使用groupBy
,这正是这种分组工作:
albums = _.groupBy tracks, (track) -> track.album
请注意,albums
中每个专辑名称的曲目将是“完整”曲目(不仅仅是名称和mp3属性)。
更新:关于性能的评论:当被要求“有效”地做某事时,我将其解释为尽可能以最直接和最干净的方式进行(我正在考虑程序员在阅读时的效率)代码);但许多人会明确地将效率与绩效联系起来。
关于性能,所有这三个解决方案都是O(n),n是轨道的数量,复杂程度;所以两者都不比其他人差。
It seems原始for
循环在现代JS引擎上的运行速度比同等的高阶兄弟快得多:forEach
,reduce
等等(IMO非常令人伤心:(。 ..)。所以第一个版本应该比第二个版本运行得快。
在Underscore版本的情况下,我不会做任何预测,因为已知Underscore使用更高阶函数很多而不是原始for
循环,但是同时,该版本不会为每个轨道创建新对象。
在任何情况下,在将解决方案更改为可能性能更高但可读性较差的解决方案之前,您应始终对代码进行概要分析。如果您注意到该特定循环是一个瓶颈,并且您有一组很好的数据可以对其进行基准测试,那么jsPerf可能非常有用:)