如何使用underscore.js生成扁平化结果

26

这个 JSON 对象是:

var data = [{"Parent":1,"Child":[4,5,6]},{"Parent":2},{"Parent":3}]

如何使用underscore.js的chain/map/pluck等函数来获取平铺结果?

     var result = [];
for (var i = 0; i < data.length; i++) {
    result.push(data[i].Parent);
    if (data.Child != undefined) {
        for (var j = 0; j < data[i].Child.length; j++) {
            result.push(data[i].Child[j]);
        }
    }
}
console.log(result) >> //1,4,5,6,2,3

1
你想要实现什么目标?是将“父级”数值排序并按照“子级”数值排序吗? - alessioalex
4个回答

46

这里有一个更短的解决方案:

flat = _.flatten(_.map(data, _.values)) 

扁平化可以忽略吗?var flat = _.map(data, _.values); http://jsfiddle.net/Dk2MY/1/ - Kuroro
1
@Kuroro,alert 不会显示数组嵌套,请尝试使用 console.log - 你将看到 map() 的结果是嵌套的,所以仍然需要使用 flatten()。 - georg
请注意,这也会获取数据对象中其他属性的值。只要您只有“Parent”和“Child”,那么您应该没问题。 - Tikhon Jelvis
6
让我们让单子发挥作用 :-) _.chain(data).map(_.values).flatten().value() 的翻译是:将数据传入_.chain函数,先使用map方法取出对象所有属性的值,再使用flatten方法展开多维数组,最后使用value方法返回结果。 - Marco Faustinelli
像这样:_.flatten(_.map(data)) 真是太棒了!谢谢! - Thiago C. S Ventura

14

如果您想要一个能够普遍扁平化任何对象或数组集合的函数,您可以扩展Underscore:

您可以使用以下方式扩展Underscore:

_.mixin({crush: function(l, s, r) {return _.isObject(l)? (r = function(l) {return _.isObject(l)? _.flatten(_.map(l, s? _.identity:r)):l;})(l):[];}});

Crush(暂无更好的名称)可以使用_.crush(list, [shallow])_(list).crush([shallow])来调用,其行为与Underscore内置的Flatten完全相同。

它可以传递任意深度的嵌套对象、数组或二者组合的集合,并返回包含所有输入值和自身属性的单级数组。与Flatten类似,如果传递了一个解析为true的附加参数,则执行“浅层”操作,仅将输出扁平化一层。

示例1:

_.crush({
   a: 1,
   b: [2],
   c: [3, {
      d: {
         e: 4
      }
   }]
});

//=> [1, 2, 3, 4]

示例2:

_.crush({
   a: 1,
   b: [2],
   c: [3, {
      d: {
         e: 4
      }
   }]
}, true);

//=> [1, 2, 3, {
//      d: {
//         e: 4
//      }
//   }]

代码本身的解释如下:

_.mixin({  // This extends Underscore's native object.

  crush: function(list, shallow, r) {  // The "r" is really just a fancy
                                       // way of declaring an extra variable
                                       // within the function without
                                       // taking up another line.

    return _.isObject(list)?  // Arrays (being a type of object)
                              // actually pass this test too.

      (r = function(list) {  // It doesn't matter that "r" might have
                             // been passed as an argument before,
                             // as it gets rewritten here anyway.

        return _.isObject(list)?  // While this test may seem redundant at
                                  // first, because it is enclosed in "r",
                                  // it will be useful for recursion later.

          _.flatten(_.map(list, shallow?  // Underscore's .map is different
                                          // from plain Javascript's in
          // _.map will always return     // that it will apply the passed
          // an array, which is why we    // function to an object's values
          // can then use _.flatten.      // as well as those of an array.

            _.identity  // If "shallow" is truthy, .map uses the identity
                        // function so "list" isn't altered any further.

            : r  // Otherwise, the function calls itself on each value.
          ))
          : list  // The input is returned unchanged if it has no children.
        ;
      })(list)  // The function is both defined as "r" and executed at once.

      : []  // An empty array is returned if the initial input
    ;       // was something other than an object or array.
  }
});

希望这能帮到需要的人。 :)

11

假设你想先获取父级节点,再获取子节点:

_.chain(data).pluck("Parent")
             .concat(_.flatten(_(data).pluck("Child")))
             .reject(_.isUndefined)
             .value()

谢谢!这个使用了 underscore.js 库,比我的代码简单多了。 - Kuroro
很高兴听到你喜欢它。你应该尝试一下函数式编程——它使得像这样编写代码更加自然,并教会你以新的方式思考。Underscore只是为JavaScript提供了一堆函数式特性。 - Tikhon Jelvis

0
如果您想使用underScore.js将由多个数组组成的数组平铺成一个元素数组,那么可以按照以下示例进行操作:
我的图表有两个系列。每个系列都有一个名称和一系列数据点{xtime,yValue}。我的目标是将2个系列中的所有数据点展开到一个数据点系列中,以填充表格。
var reducedArray = // flatten an array of series of data-objects into one series of data-objects
_.flatten( _.map( AllMySeries, function ( aSeries ) {
    return ( _.map( aSeries.dataPoints, function ( aPoint ) {
                return { curveID: aSeries.legendText, xT: aPoint.x, yVal: aPoint.y };
            } ) );
} ) );

我的结果:

'Series1','2017-04-19 08:54:19',1
'Series1','2017-04-19 08:59:19',0
'Series1','2017-04-19 09:04:19',1
'Series2','2017-04-19 08:54:19',1
'Series2','2017-04-19 08:59:19',0
'Series2','2017-04-19 09:04:19',1  

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接