【问题标题】:Rearrange an array of objects based on a common key/value pair基于公共键/值对重新排列对象数组
【发布时间】:2017-11-11 05:39:12
【问题描述】:

我有以下对象数组:

[
   {
     message: 'This is a test',
     from_user_id: 123,
     to_user_id: 567
   },
   {
     message: 'Another test.',
     from_user_id: 123,
     to_user_id: 567
   },
   {
     message: 'A third test.',
     from_user_id: '456',
     to_user_id: 567
   }
]

如何构造一个新的对象数组,其中最外层的对象键基于在原始数组中找到的公共键?

这就是我所追求的:

[
  {
    123: [
      {
        message: 'This is a test',
        from_user_id: 123,
        to_user_id: 567
      },
      {
        message: 'Another test.',
        from_user_id: 123,
        to_user_id: 567
      }
    ]
  },
  {
    456: [
      {
        message: 'A third test.',
        from_user_id: '456',
        to_user_id: 567
      }
    ]
  }
]

注意在第一个数组中,123 的用户 ID 是如何出现在两个对象中的。这将是新数组中第一个元素的对象键。

【问题讨论】:

    标签: javascript arrays json multidimensional-array javascript-objects


    【解决方案1】:

    您可以使用一个对象并将from_user_id 属性作为该对象的键。然后将实际对象推送到组中。为了获得最终结果,迭代groups 的键并为任何组构建一个新对象。

    var data = [{ message: 'This is a test', from_user_id: 123, to_user_id: 567 }, { message: 'Another test.', from_user_id: 123, to_user_id: 567 }, { message: 'A third test.', from_user_id: '456', to_user_id: 567 }],
        groups = Object.create(null),
        result;
    
    data.forEach(function (a) {
        groups[a.from_user_id] = groups[a.from_user_id] || [];
        groups[a.from_user_id].push(a);    
    });
    
    result = Object.keys(groups).map(function (k) {
        var temp = {};
        temp[k] = groups[k];
        return temp;
    });
    
    console.log(result);
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    结合单循环方法

    var data = [{ message: 'This is a test', from_user_id: 123, to_user_id: 567 }, { message: 'Another test.', from_user_id: 123, to_user_id: 567 }, { message: 'A third test.', from_user_id: '456', to_user_id: 567 }],
        result = data.reduce(function (groups) {
            return function (r, a) {
                var temp = {};
                if (!groups[a.from_user_id]) {
                    groups[a.from_user_id] = [];
                    temp[a.from_user_id] = groups[a.from_user_id]; 
                    r.push(temp);
                }
                groups[a.from_user_id].push(a);
                return r;
            };
        }(Object.create(null)), []);
    
    console.log(result);
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    【讨论】:

    • 你能解释一下这是怎么回事吗=> groups[a.from_user_id] = groups[a.from_user_id] || [];
    • 如果对象中不存在键a.from_user_id,则返回undefined,然后默认值,取一个空数组并赋值。 || 是逻辑 OR,有时称为 默认运算符
    • 由于您不能在undefined 上使用.push(),而只能在数组上为空或不为空,我们需要确保groups[...] 是某个东西或一个空列表。
    • 不错的方法,但这将返回一个对象而不是数组!!! OP 希望有一个数组作为结果。
    • @NinaScholz 干得好,这真是一件艺术品 :)
    【解决方案2】:

    您可以使用全功能获取所有关键过滤器并将其映射回 json 对象

    var b = a.map(key => key['from_user_id'])
    var c = {}
    b.map(elt => c[elt] = a.filter(k => k.from_user_id == elt))
    console.log(c)
    

    【讨论】:

    • 谢谢!尽管有两个循环,但它用 [看起来] 更少的代码行来完成,这总是很棒。
    【解决方案3】:

    你只需要初始化一个results数组,遍历你的数据数组,检查results数组中是否存在迭代的from_user_id,把迭代的对象推到上面,否则用新的创建一个新对象from_user_id 键。

    这应该是你的代码:

    var results = [];
    arr.forEach(function(obj){
        let id = obj["from_user_id"];
        if(!results.some(function(r){
           return r[id];
        })){
            let el = {}; 
            el[id] = [];
            el[id].push(obj);
            results.push(el);
        }else{
            results.forEach(function(res){
                if(res[id]){
                  res[id].push(obj);
                }
            });
        }
    });
    

    演示:

    var arr = [{
      message: 'This is a test',
      from_user_id: 123,
      to_user_id: 567
    }, {
      message: 'Another test.',
      from_user_id: 123,
      to_user_id: 567
    }, {
      message: 'A third test.',
      from_user_id: 456,
      to_user_id: 567
    }];
    
    
    var results = [];
    arr.forEach(function(obj){
        let id = obj["from_user_id"];
        if(!results.some(function(r){
           return r[id];
        })){
            let el = {}; 
            el[id] = [];
            el[id].push(obj);
            results.push(el);
        }else{
            results.forEach(function(res){
                if(res[id]){
                  res[id].push(obj);
                }
            });
        }
    });
    console.log(results);

    【讨论】:

    • 谢谢! :) 我试图避免双循环,但这似乎是最常见的方式。
    【解决方案4】:

    var users = [
                 {
                   message: 'This is a test',
                   from_user_id: 123,
                   to_user_id: 567
                 },
                 {
                   message: 'Another test.',
                   from_user_id: 123,
                   to_user_id: 567
                 },
                 {
                   message: 'A third test.',
                   from_user_id: '456',
                   to_user_id: 567
                 }
              ];
    console.log(_.groupBy(users,'from_user_id'))
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

    使用Lodash 会让您非常轻松。假设你有:

    var users = [
                 {
                   message: 'This is a test',
                   from_user_id: 123,
                   to_user_id: 567
                 },
                 {
                   message: 'Another test.',
                   from_user_id: 123,
                   to_user_id: 567
                 },
                 {
                   message: 'A third test.',
                   from_user_id: '456',
                   to_user_id: 567
                 }
              ];
    

    只需与Lodash 在一行中,你会得到你想要的

    users = _.groupBy(users,'from_user_id')
    

    【讨论】:

    • 我没有尝试使用 Lodash,因为我试图在 vanilla JS 中这样做,但这绝对是个好消息!谢谢!
    • 欢迎您!应该试一试:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-13
    • 2018-05-01
    • 1970-01-01
    • 2019-02-21
    相关资源
    最近更新 更多