【问题标题】:Compare two arrays of objects and if value for a certain key is missing, add an object with that value to the array - two ways比较两个对象数组,如果缺少某个键的值,则将具有该值的对象添加到数组中 - 两种方式
【发布时间】:2020-04-03 21:21:45
【问题描述】:

我有一个数组,其中的对象的键与另一个具有相同键的对象数组匹配,第一个键的值是月份索引(0 = 一月,1 = 二月等)和积分可能会跨越一年 (a:10, a:11, a:0, a:1)

但是第一个数组可能有不同数量的对象,并且一个对象上的键的值可能不存在于同一键上的另一个对象中,反之亦然。

假设两个数组都已正确排序,我想比较这两个数组,如果一个数组缺少一个对象,而另一个数组的键值为另一个数组,我想向第一个数组添加一个新对象具有相同的键和值,在没有它的数组中的相同位置/索引中,就像在有它的数组中一样。

let arr1 = [{a:0, b:1},{a:1, b:3},{a:3, b:18},{a:4, b:2}]
let arr2 = [{a:10, b:2},{a:11, b:4},{a:0, b:8},{a:1, b:5},{a:2, b:1}]

arr1 缺少存在于arr2 中的a 值为10、11 和2 的对象,而arr2 缺少存在于@ 中的a 值为3 和4 的对象987654331@

我想结束的是

arr1 = [{a:10, b:0},{a:11, b:3},{a:0, b:1},{a:1, b:3},{a:2, b:0},{a:3, b:18},{a:4, b:2}]
arr2 = [{a:10, b:2},{a:11, b:4},{a:0, b:8},{a:1, b:5},{a:2, b:1},{a:3, b:0},{a:4, b:0}]

现在arr1 拥有a:10a:11a:2 的新项目/对象,而 arr2a:3a:4 的新项目,所有这些项目的 b 值为 0;

我尝试在纸上将其绘制出来,以从逻辑上了解我会在物理上做什么,但我就是无法理解它,所以“傻瓜”的答案会非常有帮助。我以为我已经学到了足够的知识来就业,但这真的让我很难受,而且它只是一个简单的 HTML5 画布线图。我从数据库中获取数据以比较同一图表上的两条线,其中一种类型的数据可能没有一个月的数据,但另一种类型的数据有。对于那些不存在于其中一个或另一个中的点,我想将线在 Y 轴上下降到 0,然后返回到下一个值。 https://github.com/rmgreenstreet/custom-forms/blob/master/public/javascripts/canvasRender.js

【问题讨论】:

  • 您的问题不是缺少键,而是数组中缺少值。这与您链接到的问题完全不同。
  • @Barmar 已删除

标签: javascript arrays object


【解决方案1】:

只有月份索引不适合正确排序。 只需添加一些有关年份的信息,就可以轻松完成。 如果没有排序,它可能看起来像:

// loop elements of the arr2 with reduce,
// if there is any element in arr1 with the same value of key 'a', 
// result is the same as on the previous step
// if there is no elements of that kind, add new object {'a': arr2['a'], 'b' : 0} into arr1

function newArray (arr1, arr2) {
  return arr2.reduce((result, obj2) => {
    if (arr1.some(obj1 => obj1['a'] === obj2['a'])) {
      return result;
    }
    return [...result, {['a'] : obj2['a'], 'b':0}];
  }, arr1)
}
// now you can assign the result of newArray() to new variables
const arr1_ = newArray(arr1, arr2)
const arr2_ = newArray(arr2, arr1)

OP 的最终工作函数(已将 a 值更改为 mm/yyyy 字符串:

function equalize(arr1, arr2) {
    let newArr = arr2.reduce(function (result, obj2) {
        if (arr1.some(obj1 => obj1['a'] === obj2['a'])) {
            return result;
        }
        return [...result, {'a' : obj2['a'], 'b':0}];
    }, arr1);
    newArr.sort(function (a, b) {
        console.log(`a: ${a}`)
        a = a.x.split('/');
        b = b.x.split('/')
        return new Date(a[1], a[0], 1) - new Date(b[1], b[0], 1)
    });
    return newArr;
};

【讨论】:

  • 对于该排序,您是否建议分别设置月份和年份的键/值对?还是在一个键/值中同时包含月/年?
【解决方案2】:

这个任务的主要烦恼是检查是否存在具有特定值a 的项目。一个简单直接的解决方案需要在 arr2 上迭代 arr1 的每一项,反之亦然,这使得它成为 O(n2),即慢。

另一种方法建议使用对象作为快速查找图。这个想法是把你的数组翻过来,使用as 作为键,使用bs 作为值。

let arr1 = [{a:1, b:1},{a:2, b:3},{a:4, b:18},{a:5, b:2}]
let arr2 = [{a:2, b:2},{a:3, b:4},{a:4, b:8},{a:6, b:5},{a:7, b:1}]

// Using objects as lookup maps.
let m1 = {}
let m2 = {}

// Filling the maps.
// The 'a' becomes a key, the 'b' becomes a value.
arr1.forEach(v => m1[v.a] = v.b)
arr2.forEach(v => m2[v.a] = v.b)

// Iterating over the keys of m1, checking if m2 has that key,
// if not - adding it with a value of 0.
for (let f in m1) m2[f] || (m2[f] = 0)

// The same goes for m2 -> m1.
for (let f in m2) m1[f] || (m1[f] = 0)

// At this point both m1 & m2 have all the keys from both arrays without gaps.

let res1 = []
let res2 = []

// Assembling the resulting arrays.
for (let f in m1) res1.push({a: f, b: m1[f]})

for (let f in m2) res2.push({a: f, b: m2[f]})

请原谅我喜欢单线。

【讨论】:

    【解决方案3】:

    这是我的解决方案。我将 lodash 用于辅助函数。

    function combineArrays (a, b) {
      Object.keys(b).forEach(function (k) {
        const key = parseInt(k);
        if (!a[key]) {
          a[key] = b[key];
          a[key].b = 0;
        }
      });
    
      return _.values(a);
    }
    

    工作代码sn-p

    // const arr1 = [{ a: 1, b: 1 }, { a: 2, b: 3 }, { a: 4, b: 18 }, { a: 5, b: 2 }];
    // const arr2 = [{ a: 2, b: 2 }, { a: 3, b: 4 }, { a: 4, b: 8 }, { a: 6, b: 5 }, { a: 7, b: 1 }];
    
    let arr1 = [{a:0, b:1},{a:1, b:3},{a:3, b:18},{a:4, b:2}]
    let arr2 = [{a:10, b:2},{a:11, b:4},{a:0, b:8},{a:1, b:5},{a:2, b:1}]
    
    const arr1Map = _.keyBy(arr1, 'a');
    const arr2Map = _.keyBy(arr2, 'a');
    
    function combineArrays(a1Map, a2Map) {
      const a = _.cloneDeep(a1Map);
      const b = _.cloneDeep(a2Map);
    
      Object.keys(b).forEach(function(k) {
        const key = parseInt(k);
        if (!a[key]) {
          a[key] = b[key];
          a[key].b = 0;
        }
      });
    
      return _.values(a);
    }
    
    console.log(combineArrays(arr1Map, arr2Map));
    console.log(combineArrays(arr2Map, arr1Map));
    <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.15/lodash.min.js"></script>

    【讨论】:

    • 不幸的是,这对我不起作用,因为必须保留订单
    【解决方案4】:

    您应该遍历第一个数组,并检查每个键是否在第二个数组中。如果不是,您应该使用arr.splice() 插入一个项目。

    如果您知道两个列表都已排序,即键是按顺序排列的,那么您也可以不需要检查整个数组的新键。

    let j = 0;
    for (let i = 0; i < arr1.length; i++) {
      let possiblyMissingKey = arr1[i].a;
      while (arr2[j].a < possiblyMissingKey && j < arr2.length)
        j++;
      if (arr2[j].a != possiblyMissingKey) {
        let itemToInsert = {a:possiblyMissingKey, b:0};
        arr2.splice(j, 0, itemToInsert);
      }
    }
    

    完成第一个数组后,执行第二个数组。

    【讨论】:

    • 我觉得这很接近,但我没有提到a 的值是一个月指数,其中0 = 一月,1 = 二月等,它是它可能会跨越年份边界,因此它可能会变为 a:10、a:11、a:0、a:1。我会更新问题。
    猜你喜欢
    • 2019-01-04
    • 2022-06-10
    • 2021-06-15
    • 1970-01-01
    • 2019-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多