【问题标题】:Comparing two arrays of objects for matching properties then creating two new arrays比较两个对象数组以匹配属性,然后创建两个新数组
【发布时间】:2021-09-28 09:05:23
【问题描述】:

我有以下两个数组:

var oldOrder = [{"Id": "10","Qty": 1}, {"Id": "3","Qty": 2}, {"Id": "9","Qty": 2}]; 
var newOrder = [{"Id": "5","Qty": 2},{"Id": "10","Qty": 3}, {"Id": "9","Qty": 1}];

我需要最终得到一个 newArray,每个 Id 只包含一个对象,但如果 oldOrder 数组和 newOrder 数组中的对象中的 id 则我需要得到 Qty 正数或负数的差异。因此,例如上面将创建这个新数组:

var newArray = [{"Id": "5","Qty": 2},{"Id": "10","Qty": 2}, {"Id": "9","Qty": -1}];

我还想获取 oldOrder 数组中存在但 newOrder 数组中不存在的已删除订​​单:

var droppedOrders = [{"Id": "3","Qty": 2}];

我已经有了这个逻辑来获取丢弃的订单,但我正在努力创建 newArray 并将逻辑绑定到同一个函数中(如果可能)?

function comparer(otherArray){
  return function(current){
    var onlyInOld = otherArray.filter(function(other){
      return other.Id == current.Id;
    }).length == 0;
    return onlyInOld;
  }
}

var droppedOrders= oldOrder.filter(comparer(newOrder));
console.log(droppedOrders);

编辑添加我不能使用 ESC6 功能,如展开或粗箭头等。

【问题讨论】:

    标签: javascript arrays object


    【解决方案1】:

    您可以使用Map轻松实现结果

    1) 使用 ES6

    var oldOrder = [
      { Id: "10", Qty: 1 },
      { Id: "3", Qty: 2 },
      { Id: "9", Qty: 2 },
    ];
    var newOrder = [
      { Id: "5", Qty: 2 },
      { Id: "10", Qty: 3 },
      { Id: "9", Qty: 1 },
    ];
    
    const oldMap = new Map(oldOrder.map((o) => [o.Id, o]));
    const newMap = new Map(newOrder.map((o) => [o.Id, o]));
    
    const result = newOrder.map((o) =>
      oldMap.has(o.Id) ? { ...o, Qty: o.Qty - oldMap.get(o.Id).Qty } : o
    );
    
    const droppedOrders = oldOrder.filter(({ Id }) => !newMap.has(Id));
    
    console.log(result);
    console.log(droppedOrders);
    /* This is not a part of answer. It is just to give the output fill height. So IGNORE IT */
    
    .as-console-wrapper {
      max-height: 100% !important;
      top: 0;
    }

    2) 使用 ES5

    var oldOrder = [
      { Id: "10", Qty: 1 },
      { Id: "3", Qty: 2 },
      { Id: "9", Qty: 2 },
    ];
    var newOrder = [
      { Id: "5", Qty: 2 },
      { Id: "10", Qty: 3 },
      { Id: "9", Qty: 1 },
    ];
    
    const oldMap = {};
    const newMap = {};
    oldOrder.forEach(function (o) {
      oldMap[o.Id] = o;
    });
    newOrder.forEach(function (o) {
      newMap[o.Id] = o;
    });
    
    const result = newOrder.map(function (o) {
      return oldMap[o.Id]
        ? Object.assign({}, o, { Qty: o.Qty - oldMap[o.Id].Qty })
        : o;
    });
    
    const droppedOrders = oldOrder.filter(function (o) {
      return !newMap[o.Id];
    });
    
    console.log(result);
    console.log(droppedOrders);
    /* This is not a part of answer. It is just to give the output fill height. So IGNORE IT */
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    【讨论】:

    • 对不起,我没有在我的问题中提到,但由于设备较旧,我无法在代码中使用 ESC6,有没有没有传播运算符的方法?
    • @user16824066 那么你不能同时使用Map。对吗?
    • 对不起,我想我错了,我知道胖箭头函数和扩展运算符在编译时会破坏我的代码,但是 map 确实可以工作,是否有没有扩展运算符的代码版本?我可以修改箭头函数。
    • 我已经更新了完全兼容 ES5 的代码。看一看。两个版本都添加了
    【解决方案2】:

    尝试使用Array.map 和Array.filter

    var oldOrder = [{ "Id": "10", "Qty": 1 }, { "Id": "3", "Qty": 2 }, { "Id": "9", "Qty": 2 }];
    var newOrder = [{ "Id": "5", "Qty": 2 }, { "Id": "10", "Qty": 3 }, { "Id": "9", "Qty": 1 }];
    
    const newArray = newOrder.map((node) => {
      const nodeFromOldArray = oldOrder.find((item) => item.Id === node.Id);
      if (nodeFromOldArray) {
        return {
          Id: node.Id,
          Qty: nodeFromOldArray.Qty - node.Qty
        }
      } else {
        return node;
      }
    });
    
    const droppedOrders = oldOrder.filter((item) => !newArray.find(node => node.Id === item.Id))
    
    console.log(newArray);
    console.log(droppedOrders);

    【讨论】:

      【解决方案3】:

      实现此目的的一种方法是通过 Id 键入新旧顺序数组。键入其他所有内容后应该像使用过滤器和映射一样简单:

      var oldOrder = [{"Id": "10","Qty": 1}, {"Id": "3","Qty": 2}, {"Id": "9","Qty": 2}]; 
      var newOrder = [{"Id": "5","Qty": 2},{"Id": "10","Qty": 3}, {"Id": "9","Qty": 1}];
          
      var keyedOldOrder = keyBy(oldOrder, 'Id');
      var keyedNewOrder = keyBy(newOrder, 'Id');
      
      var newArray = newOrder.map(function (entity) {
        var subtract = keyedOldOrder.hasOwnProperty(entity.Id)
          ? keyedOldOrder[entity.Id].Qty
          : 0;
        return Object.assign({}, entity, {
          Qty: entity.Qty - subtract
        });
      });
      
      var droppedOrders = oldOrder.filter(function (entity) {
        return !keyedNewOrder.hasOwnProperty(entity.Id);
      });
      
      console.log(newArray);
      console.log(droppedOrders);
      
      function keyBy(array, field)
      {
        return array.reduce(function (carry, entity) {
          carry[entity[field]] = entity;
          return carry;
        }, {});
      }

      【讨论】:

        【解决方案4】:

        您可以使用 Map 并为每个数组执行一个循环,并将结果重新发送到所需的目标数组。

        const
            addToMap = (map, target) => ({ Id, Qty }) => map.set(Id, { target, Qty: Qty - (map.get(Id)?.Qty || 0) }),
            oldOrder = [{ Id: "10", Qty: 1 }, { Id: "3", Qty: 2 }, { Id: "9", Qty: 2 }],
            newOrder = [{ Id: "5", Qty: 2 }, { Id: "10", Qty: 3 }, { Id: "9", Qty: 1 }],
            map = new Map,
            orders = [],
            dropped = [];
        
        oldOrder.forEach(addToMap(map, dropped));
        newOrder.forEach(addToMap(map, orders));
        
        map.forEach(({ target, Qty }, Id) => target.push({ Id, Qty }));
        
        console.log(orders);
        console.log(dropped);
        .as-console-wrapper { max-height: 100% !important; top: 0; }

        采用对象而不是 Map 的旧 Javascript 方法。

        算法同上。

        const
            addToMap = function(map, target) {
                return function (o) {
                    map[o.Id] = { target: target, Qty: o.Qty - (map[o.Id] && map[o.Id].Qty || 0) };
                };
            },
            oldOrder = [{ Id: "10", Qty: 1 }, { Id: "3", Qty: 2 }, { Id: "9", Qty: 2 }],
            newOrder = [{ Id: "5", Qty: 2 }, { Id: "10", Qty: 3 }, { Id: "9", Qty: 1 }],
            map = {},
            orders = [],
            dropped = [];
        
        oldOrder.forEach(addToMap(map, dropped));
        newOrder.forEach(addToMap(map, orders));
        
        Object
            .keys(map)
            .forEach(function(Id) {
                map[Id].target.push({ Id: Id, Qty: map[Id].Qty });
            });
        
        console.log(orders);
        console.log(dropped);
        .as-console-wrapper { max-height: 100% !important; top: 0; }

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-05-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-02-04
          • 2022-01-02
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多