【问题标题】:Javascript merge two objects based on keyJavascript基于键合并两个对象
【发布时间】:2016-11-17 14:01:05
【问题描述】:

我有一些如下形状的物体。

[{
    product: 'ABC',
    productId: 'AB123',
    batch: 'BA1',
    price: '12'
}, {
    product: 'ABC',
    productId: 'AB123',
    batch: 'BA2',
    price: '15'
}, {
    product: 'XYZ',
    productId: 'AB124',
    batch: 'XY1',
    price: '124'
}]

如果密钥对(product 和 productId)按以下格式计算,我想将对象合并到数组中的一个对象中。

[{
    product: 'ABC',
    productId: 'AB123',
    batch: ['BA1', 'BA2'],
    price: ['12', '15']
}, {
    product: 'XYZ',
    productId: 'AB124',
    batch: 'XY1',
    price: '124'
}]

我怎样才能在 lodash 或纯 javascript 中做到这一点。

【问题讨论】:

  • 分享您的研究对每个人都有帮助。告诉我们您尝试了什么以及为什么它不能满足您的需求。这表明您已经花时间尝试帮助自己,它使我们免于重复明显的答案,最重要的是它可以帮助您获得更具体和相关的答案!另见how to ask
  • 预期的结果对象包含不同的结构。如果一个产品有多个条目,那么您有一个批次和价格数组,但如果没有,那么您只需要一个值。 - 生成的对象不应该遵循通用格式吗?即:始终为批次/价格数组,或者甚至可能是一个包含价格和批次对象的单个数组,以便您知道哪个批次属于哪个价格?

标签: javascript lodash


【解决方案1】:

此提案不会更改给定数据。

它创建新对象,首先只使用单个数据,然后如果需要对更多数据进行分组,它使用batch 和price 的数组。

var data = [{ product: 'ABC', productId: 'AB123', batch: 'BA1', price: '12' }, { product: 'ABC', productId: 'AB123', batch: 'BA2', price: '15' }, { product: 'XYZ', productId: 'AB124', batch: 'XY1', price: '124'}],
    merged = [];

data.forEach(function (a) {
    if (!this[a.productId]) {
        this[a.productId] =  { product: a.product, productId: a.productId, batch: a.batch, price: a.price };
        merged.push(this[a.productId]);
        return;
    }
    if (!Array.isArray(this[a.productId].batch)) {
        this[a.productId].batch = [this[a.productId].batch];
    }
    if (!Array.isArray(this[a.productId].price)) {
        this[a.productId].price = [this[a.productId].price];
    }
    this[a.productId].batch.push(a.batch);
    this[a.productId].price.push(a.price);
}, Object.create(null));

console.log(merged);

【讨论】:

  • 这次没有你的班轮吗? :D
  • @fafl,加油!
  • 你太棒了! @NinaScholz
【解决方案2】:

您可以使用_.uniqWith 循环遍历集合并删除重复项。除此之外,uniqWith 还允许您访问对象本身,以便您可以随意篡改它们。

在这种情况下,当找到重复项时,我将其批次和价格添加到原始对象的数组中,得到所需的结果。

var arr = [{
  product: 'ABC',
  productId: 'AB123',
  batch: 'BA1',
  price: '12'
}, {
  product: 'ABC',
  productId: 'AB123',
  batch: 'BA2',
  price: '15'
}, {
  product: 'XYZ',
  productId: 'AB124',
  batch: 'XY1',
  price: '124'
}];

function addToArray(val1, val2) {
  return _.isArray(val1) ? val1.concat(val2) : [val1].concat(val2);
}

function modifyObjs(a, b) {
  b.batch = addToArray(b.batch, a.batch);
  b.price = addToArray(b.price, a.price);
  return true;
}

function predicateAndModifier(a, b) {
  return a.product === b.product && a.productId === b.productId && modifyObjs(a, b);
}

console.log(_.uniqWith(arr, predicateAndModifier));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script>

【讨论】:

    【解决方案3】:

    Lodash 4.17.2

    _.reduce(data, function(result, item) {
        var added = _.find(result, {
            product: item.product,
            productId: item.productId
        });
        if (_.isObject(added)) {
            //!! better to merge with new object and add result to array again to avoid mutable
            added = _.mergeWith(added, item, function(addedVal, itemVal, key) {
                if (key === 'product' || key === 'productId') {
                    return addedVal;
                }
                return _.concat(addedVal, itemVal);
            });
            return result;
        }
        return _.concat(result, item);
    }, []);
    

    【讨论】:

      【解决方案4】:

      您可以使用带有_.transform() 和_.mergeWith() 的lodash 链合并数组中的相似对象:

      function mergeSimilar(arr, arrayProps) {
        // transform the array into a map object
        return _(arr).transform(function(result, item) { 
          
          // create a temp id that includes the product and productId
          var id = item.product + item.productId; 
          
          // merge the existing item with a new item
          result[id] = _.mergeWith(result[id] || {}, item, function(objValue, srcValue, key) { 
            
            // if a value exists, and it's one of the request keys, concat them into a new array
            if (!_.isUndefined(objValue) && _.includes(arrayProps, key)) {
              return [].concat(objValue, srcValue);
            }
          });
        }, {})
        .values() // get the values from the map object
        .value();
      }
      
      var arr = [{
        product: 'ABC',
        productId: 'AB123',
        batch: 'BA1',
        price: '12'
      }, {
        product: 'ABC',
        productId: 'AB123',
        batch: 'BA2',
        price: '15'
      }, {
        product: 'XYZ',
        productId: 'AB124',
        batch: 'XY1',
        price: '124'
      }];
      
      var result = mergeSimilar(arr, ['batch', 'price']);
      
      console.log(result);
      <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script>

      【讨论】:

      • 是否可以在不知道键名的情况下对多维数组执行此操作?
      • 很难说。使用示例数据和预期结果打开一个新问题。
      【解决方案5】:

      它必须是可读的吗?

      var data = [{
          product: 'ABC',
          productId: 'AB123',
          batch: 'BA1',
          price: '12'
      }, {
          product: 'ABC',
          productId: 'AB123',
          batch: 'BA2',
          price: '15'
      }, {
          product: 'ABC',
          productId: 'AB113',
          batch: 'BA2',
          price: 15
      }, {
          product: 'XYZ',
          productId: 'AB124',
          batch: 'XY1',
          price: '124'
      }]
      var unEs6 = function(x) {
          if (x instanceof Map) {
              var result = {}
              for (let [key, value] of x.entries()) {
                  result[key] = unEs6(value);
              }
              return result;
          }
          else {
              return x
          }
      }
      JSON.stringify(unEs6(
          data
              .map(
                  row => (new Map().set(
                      row.product, new Map().set(
                          row.productId, new Map()
                              .set("batch", [row.batch])
                              .set("price", [row.price])
                          )
                      )
                  )
              )
              .reduce((a, b) => !a.has(b.keys().next().value) ?
                  new Map([...a, ...b]) :
                  !a.get(b.keys().next().value).has(b.get(b.keys().next().value).keys().next().value) ?
                      a.set(b.keys().next().value, new Map([
                          ...a.get(b.keys().next().value),
                          ...b.get(b.keys().next().value)
                      ])) :
                      a.set(b.keys().next().value, a.get(b.keys().next().value).set(
                          b.get(b.keys().next().value).keys().next().value,
                          new Map()
                              .set("batch", a.get(b.keys().next().value).get(b.get(b.keys().next().value).keys().next().value).get("batch")
                                    .concat(b.get(b.keys().next().value).get(b.get(b.keys().next().value).keys().next().value).get("batch"))
                              )
                              .set("price", a.get(b.keys().next().value).get(b.get(b.keys().next().value).keys().next().value).get("price")
                                    .concat(b.get(b.keys().next().value).get(b.get(b.keys().next().value).keys().next().value).get("price"))
                              )
                      ))
              )
      ))
      

      【讨论】:

        猜你喜欢
        • 2015-06-08
        • 2018-04-01
        • 1970-01-01
        • 2018-05-03
        • 2021-09-19
        • 1970-01-01
        • 2021-01-27
        • 1970-01-01
        相关资源
        最近更新 更多