在JavaScript中合并两个字典数组

6

我有两个字典数组,其格式大致如下:

var lat = [{key:"2017-09-20T11:51:32.000Z", value:50.7825333},{key:"2017-09-20T11:51:33.000Z", value:50.7826},...];
var lon = [{key:"2017-09-20T11:51:32.000Z", value:-1.3075833},{key:"2017-09-20T11:51:33.000Z", value:-1.3076},...];

你可能已经猜到了,一个数组是纬度,一个是经度!

我希望找到一种优雅的方法,将时间、纬度和经度合并成一个数组。两个数组包含相同的键(我应该检查这是否总是正确的!)。

var latLon = [{time:"2017-09-20T11:51:32.000Z", lat:50.7825333, lon:-1.3075833},...]

我已经拼凑出了一个工作的东西,但不够美观 (即迭代两个数组并将其附加到新的数组中),但感觉使用 Object.assign 和一些漂亮的 lambda 表达式应该有更加优雅的方式。如果 D3.js 库包含任何有用的方法,则也可以使用。


4
最好您将尝试过的代码添加到您的问题中。 - Andy
1
我正在工作,没有太多时间来确保这是正确的,但你可以查看lodash和/或underscore的zip方法--https://lodash.com/docs/4.17.4#zip - Dexygen
3个回答

0

这是基于 key 时间的。假设没有相同的键/时间,那么你可以这样做:

var lat = [{key:"2017-09-20T11:51:32.000Z", value:50.7825333},{key:"2017-09-20T11:51:33.000Z", value:50.7826}];
var lon = [{key:"2017-09-20T11:51:32.000Z", value:-1.3075833},{key:"2017-09-20T11:51:33.000Z", value:-1.3076}];

var obj = {}, arr = lat.concat(lon);

arr.forEach(function(x){
    obj[x.key] ? obj[x.key]["lon"] = x.value : obj[x.key] = {lat: x.value, time: x.key};
});

var latlon = Object.keys(obj).map(function(x){
    return obj[x];
});

您正在将2个数组连接起来以创建一个数组。然后,您将使用时间作为键创建字典(这是假定您没有两个具有相同时间的纬度和经度的地方)。由于您知道首先获取的是纬度,因此下一个键匹配应该是经度。


0
你可以使用Array#map方法来生成新数组(假设这两个数组是按照相同的顺序排列的)。

var lat = [{key:"2017-09-20T11:51:32.000Z", value:50.7825333},{key:"2017-09-20T11:51:33.000Z", value:50.7826}];
var lon = [{key:"2017-09-20T11:51:32.000Z", value:-1.3075833},{key:"2017-09-20T11:51:33.000Z", value:-1.3076}];


var res = lat
  // iterate over the first array
  .map(function(o, i) {
    // generate the array element
    // where get values from element and
    // get value from second array using
    // the index
    return {
      time: o.key,
      lat: o.value,
      lon: lon[i].value
    }
  })

console.log(res);

// with ES6 arrow function
var res1 = lat.map((o, i) => ({time: o.key, lat: o.value, lon: lon[i].value}))


console.log(res1);


注意:如果相关的数组元素不是按照相同的顺序排列的,则需要通过比较时间值(可以使用Array#find方法)从第二个数组中获取元素,或者您可以生成一个哈希映射来映射对象。

使用Array#find方法:

var lat = [{key:"2017-09-20T11:51:32.000Z", value:50.7825333},{key:"2017-09-20T11:51:33.000Z", value:50.7826}];
var lon = [{key:"2017-09-20T11:51:32.000Z", value:-1.3075833},{key:"2017-09-20T11:51:33.000Z", value:-1.3076}];



var res = lat
  .map(function(o) {
    return {
      time: o.key,
      lat: o.value,
      // get object by using find method
      lon: lon.find(function(o1) {
        return o1.key === o.key;
      }).value
    }
  })

console.log(res);

// with ES6 arrow function
var res1 = lat.map(o => ({
  time: o.key,
  lat: o.value,
  lon: lon.find(o1 => o1.key === o.key).value
}))

console.log(res1);

使用哈希映射进行引用的更高效方法:

var lat = [{key:"2017-09-20T11:51:32.000Z", value:50.7825333},{key:"2017-09-20T11:51:33.000Z", value:50.7826}];
var lon = [{key:"2017-09-20T11:51:32.000Z", value:-1.3075833},{key:"2017-09-20T11:51:33.000Z", value:-1.3076}];

// generate reference hashmap for getting 
// value using the datetime string
var ref = lon.reduce(function(obj, o) {
  // set reference
  obj[o.key] = o.value;
  // return the reference object
  return obj;
  // set initial value as an empty object
}, {});

var res = lat
  .map(function(o) {
    return {
      time: o.key,
      lat: o.value,
      // get value from generated reference object
      lon: ref[o.key]
    }
  })

console.log(res);


0

如果有可能你将处理大量的项目,我建议避免使用find()find()需要在第二个数组中搜索每个不高效的

如果您在第一次循环中构建了一个字典,并在第二次循环中创建了新数组,则可以使用单个mapreduce完成此操作。

这还允许latlon数组按不同的顺序排列。

var lat = [{key:"2017-09-20T11:51:32.000Z", value:50.7825333},{key:"2017-09-20T11:51:33.000Z", value:50.7826}];
var lon = [{key:"2017-09-20T11:51:32.000Z", value:-1.3075833},{key:"2017-09-20T11:51:33.000Z", value:-1.3076}];

var obj = lat.reduce((a, c) => (a[c.key] = {time: c.key, lat:c.value}, a), {});
var arr = lon.map(lon => Object.assign(obj[lon.key], {lon: lon.value}));

console.log(arr);


如果你可能会处理大量项目,我建议避免使用find()。实际上,使用find()将循环直到找到所需的对象,而使用你现有的代码,你将两次遍历整个数组,一次使用reduce(),另一次使用.map(),因此我认为使用find()将更具性能。 ;) - cнŝdk
@chsdk,你的答案中的find()map()内部,这意味着find()会针对lat中的每个项目进行调用。如果有100个项目,则会调用100次find()。这比两个循环要糟糕得多。 - Mark
是的,我同意你的观点。如果有很多项(顺便说一下,100个并不算太多),但是find()会在找到object后立即停止查找,理论上来说它的效率更低,但它们被实现为保证性能。但是,如果两个数组中的对象按相同的方式排序,所有这些问题都将被真正省略。 但无论如何,不要从你提供的绝妙解决方案中削减任何东西。 :) - cнŝdk
你正在使用ES6箭头函数,那么浏览器对它们的支持如何? - doubleOrt
@Taurus 看起来全球使用箭头函数的浏览器支持率略低于80%。https://caniuse.com/#feat=arrow-functions - Mark
@Mark_M 非常好,我从未想过会这么多。 - doubleOrt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接