【问题标题】:JS Lodash: Multidimensional array to object, with a twistJS Lodash:多维数组到对象,有点扭曲
【发布时间】:2014-04-03 18:17:19
【问题描述】:

我从这样的多维数组开始:

[
    ['prop1', 'prop2', 'prop3', 'prop3'],
    ['val1', 'val2', 'val3', 'val4']
]

我需要将它转换成这样的对象:

{ prop1: 'val1',
  prop2: 'val2',
  prop3: ['val3', 'val4']
}

通常我可以使用_.object(array[0], array[1]) 来解决这个问题,但是重复键prop3 的存在使事情变得相当复杂;

实际的_.object 将设置prop3: 'val4',擦除val3

有人知道我如何实现上述结果吗?

谢谢

【问题讨论】:

  • 数组中总是有 2 个项目还是可以有更多?
  • 这些重复的属性名称是否总是彼此相邻?值也可以是数组吗?
  • 回答这两个问题: - 每个键可以有超过 1 个重复项 - 不,它们不一定在数组中相邻 --- PS:我们不能至少在这些评论?似乎无法格式化

标签: javascript object multidimensional-array underscore.js lodash


【解决方案1】:

我可能会做这样的事情,这很容易变成下划线混合:

var arr = [
    ['prop1', 'prop2', 'prop3', 'prop3'],
    ['val1', 'val2', 'val3', 'val4']
],
    keys = arr[0],
    vals = arr[1],
    obj = {};

keys.forEach( function( name, index )
{
    if ( !Object.prototype.hasOwnProperty.call(obj, name) )
    {
        obj[name] = vals[index];
    }
    else
    {
        if ( obj[name] instanceof Array )
        {
            obj[name].push( vals[index] );
        }
        else
        {
            var val = obj[name];
            obj[name] = [val, vals[index]];
        }
    }
} );

Example in a fiddle.(变成mixin)

jsPerf comparison with underscore-based code.

【讨论】:

  • !obj[name] 不足。如果obj[name] = false 或任何非真实值怎么办
  • 另外typeof x == 'array'也不是一回事
  • FWIW,另一个使用下划线方法的示例几乎完全以 18442.733 毫秒计时钟,而在我上面的答案中仅使用 _.each() 方法需要 5.314 毫秒。如果我把它拿出来并使用 keys.forEach() ,它会将时间缩短到 0.118 毫秒。重点是,如果您可以避免使用库,它会更快。 :)
  • obj[name].isArray 不是一个东西。你想要Array.isArray(obj[name])。注意:其中许多功能需要 ES5
  • jsfiddle.net/y6ttk/4 反映了对数组的正确检查以及将其转换为 mixin,如果您宁愿写一行(并且必须一遍又一遍地使用它),@OlivierClément。
【解决方案2】:

只需压缩数组,然后使用自定义 reduce 就可以解决问题。如果您的数据 arr 可以包含 2 个以上的集合,那么调整这一点应该很简单。

_.mixin({
   asArray: function(value) {//simple helper from https://github.com/jashkenas/underscore/pull/1467
     if (value == null) return [];
     if (value.length === +value.length && !_.isString(value)) return _.toArray(value);
     return [value];
   }
});


var arr = [
    ['prop1', 'prop2', 'prop3', 'prop3'],
    ['val1', 'val2', 'val3', 'val4']
];
/* ... */
_.chain(arr)
 .zip()
 .reduce(function(memo, propKey) {
   if(_.has(memo, propKey[0])) { // property already in the object. Make array if necessary and insert item at end
       (memo[propKey[0]] = _.asArray(memo[propKey[0]])).push(propKey[1]); //push value into object
   }
   else {
      memo[propKey[0]] = propKey[1];
   }
   return memo;
}, {})
 .value();

产生:{"prop1":"val1","prop2":"val2","prop3":["val3","val4"]}

如果你不想混入,asArray 可以很容易地替换。请参阅以前的修订版。

【讨论】:

  • @jacobroufa 如果您想对您的实现进行基准测试并制作一个 jsperf 示例
  • 修改了我的帖子以反映您建议的更改并添加 jsperf 示例比较。
  • 您好,感谢您的回答——事实上,它似乎并不能解决问题;照原样,它会导致: Object {prop1,prop2,prop3,prop3: undefined, val1,val2,val3,val4: undefined} 没有 zip: Object {prop1: "prop2", val1: "val2"} which is' t 我所追求的 --- 我不确定为什么也需要 zip,因为它似乎只是将我的数组包装成更多的数组......?
  • 哎呀,对不起,我在修订之间破坏了代码;)。我使用.zip 将您的数组分组为[key, value] 形式的子数组,以便于处理。
【解决方案3】:

为了完整起见,我想提一下这个方法:

http://lodash.com/docs#zipObject - 或(新)_.object()

创建一个由键和值数组组成的对象。提供单个二维数组,即 [[key1, value1], [key2, value2]] 或两个数组,一个键和一个对应的值。

例子

_.zipObject(['fred', 'barney'], [30, 40]);
// → { 'fred': 30, 'barney': 40 }

不幸的是,它不会将多个值组合成一个键的数组:

_.object(['key1', 'key2'], [1,2]);
// { key1: 1, key2: 2 }
_.object(['key1', 'key1'], [1,2]);
// { key1: 2 }
_.object(['key1'], [1,2]);
// { key1: 1 }

所以这并不是你答案的真正解决方案,但我认为注意这个功能仍然很有价值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-12-12
    • 2014-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多