【问题标题】:Merge objects concatenating values, using lodash使用 lodash 合并对象连接值
【发布时间】:2016-12-10 02:21:07
【问题描述】:

我正在尝试操作这个示例对象数组。

[ { name: 'John Wilson',
    id: 123,
    classes: ['java', 'c++']},
  { name: 'John Wilson',
    id: 123,
    classes: 'uml'},
   { name: 'Jane Smith',
    id: 321,
    classes: 'c++'} ]

我需要做的是合并具有相同“id”的对象,连接“类”并保留一个“名称”。

结果应该是:

[ { name: 'John Wilson',
    id: 123,
    classes: ['java', 'c++', 'uml']},
   { name: 'Jane Smith',
    id: 321,
    classes: 'c++'} ]

我尝试使用 .merge,但它不会连接“类”中的值,它只是保留最后一个相等对象的值。

使用 lodash 最简单的方法是什么?

【问题讨论】:

    标签: javascript lodash


    【解决方案1】:

    使用 ES6,您可以使用 Map 来保存唯一值,Array#reduce 来填充它,而 spread operatorMap#values 可以将其转换回数组:

    const arr = [{"name":"John Wilson","id":123,"classes":["java","c++"]},{"name":"John Wilson","id":123,"classes":"uml"},{"name":"Jane Smith","id":321,"classes":"c++"}];
    
    const result = [...arr.reduce((hash, { id, name, classes }) => {
      const current = hash.get(id) || { id, name, classes: [] };
      
      classes && (current.classes = current.classes.concat(classes));
      
      return hash.set(id, current);
    }, new Map).values()];
    
    console.log(result);

    【讨论】:

    • 这真的很聪明,很有创意。 +1 了解 ES6 的内里外外。
    【解决方案2】:

    您要查找的函数是 _.uniqWith,有一个特殊的转折,我稍后会解释。

    _.uniqWith_.uniq 很相似,因为它会生成一个唯一的数组,但它允许您传递自己的自定义比较器函数,该函数将被调用以确定什么算作“相等”。

    理智的程序员会理解这个比较器应该没有副作用。此代码的工作方式是打破该规则,并使用在幕后发挥额外作用的比较函数。但是,这会产生非常简洁的代码,无论您的数组中有多少这些对象都可以正常工作,所以我觉得这种违规行为是有道理的。

    我将比较器函数命名为compareAndMerge,以免隐藏其不纯的性质。它将合并两个 classes 数组并更新两个对象的相关属性,但前提是它们的 id 值相同。

    function merge(people) {
      return _.uniqWith(people, compareAndMerge)
    }
    
    function compareAndMerge(first, second) {
        if (first.id === second.id) {
            first.classes = second.classes = [].concat(first.classes, second.classes)
            return true
        }
        return false
    }
    
    
    var people = [{
      name: 'John Wilson',
      id: 123,
      classes: ['java', 'c++']
    }, {
      name: 'John Wilson',
      id: 123,
      classes: 'uml'
    }, {
      name: 'Jane Smith',
      id: 321,
      classes: 'c++'
    }]
    
    console.log(merge(people))
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script>

    顺便说一句:您原来的 classes 列表周围缺少方括号。我确保上面的代码并不关心 classes 属性是保存单个字符串还是字符串数组,以防万一。

    【讨论】:

    • 谢谢!我实际上忘记了括号。代码很干净,效果很好。
    • 很高兴能帮上忙!一路走来,我也学到了很多关于 lodash 的知识。
    【解决方案3】:

    不确定是否使用 lodash... 这是一种使用普通 JS 的方法:

    var combined = arr.reduce(function(a, item, idx) {
        var found = false;
        for (var i = 0; i < a.length; i++) {
            if (a[i].id == item.id) {
                a[i].classes = a[i].classes.concat(item.classes);
                found = true;
                break;
            }
        }
    
        if (!found) {
            a.push(item);
        }
    
        return a;
    }, []);
    

    小提琴:https://jsfiddle.net/6zwr47mt/

    【讨论】:

      【解决方案4】:

      使用_.mergeWith设置合并定制器

      _.reduce(data, function(result, item) {
          item = _.mergeWith(
              item,
              _.find(result, {id: item.id}),
              function(val, addVal) {
                  return _.isArray(val) ? _.concat(val, addVal) : val;
              });
          result = _.reject(result, {id: item.id})
          return _.concat(result, item);
      }, []);
      

      【讨论】:

        【解决方案5】:

        以下算法不是最好的,但至少我知道它的作用:-)

        console.log(clean(data));
        
        function clean (data) {
          var i, x, y;
          var clean = [];
          var m = clean.length;
          var n = data.length;
          data.sort((x, y) => x.id - y.id);
          for (i = 0; i < n; i++) {
            y = data[i];
            if (i == 0 || x.id != y.id) {
              clean.push(x = clone(y)), m++;
            } else {
              clean[m - 1] = merge(x, y);
            }
          }
          return clean;
        }
        
        function clone (x) {
          var z = {};
          z.id = x.id;
          z.name = x.name;
          z.classes = x.classes.slice();
          return z;
        }
        
        function merge (x, y) {
          var z = {};
          z.id = x.id;
          z.name = x.name;
          z.classes = unique(
            x.classes.concat(y.classes)
          );
          return z;
        }
        
        function unique (xs) {
          var i, j, n;
          n = xs.length;
          for (i = 1; i < n; i++) {
            j = 0; while (j < i && xs[i] !== xs[j]) j++;
            if (j < i) swap(xs, i, n - 1), i--, n--;
          }
          return xs.slice(0, n);
        }
        
        function swap (xs, i, j) {
          var x = xs[i];
          xs[i] = xs[j];
          xs[j] = x;
        }
        <script>
          var data = [{
            id: 123,
            name: 'John Wilson',
            classes: ['java', 'c++']
          }, {
            id: 123,
            name: 'John Wilson',
            classes: ['uml', 'java']
          }, {
            id: 321,
            name: 'Jane Smith',
            classes: ['c++']
          }];
        </script>

        【讨论】:

          猜你喜欢
          • 2018-08-07
          • 2019-05-30
          • 1970-01-01
          • 2016-12-28
          • 2019-12-04
          • 2016-06-12
          • 1970-01-01
          • 2019-05-07
          • 1970-01-01
          相关资源
          最近更新 更多