【问题标题】:D3 - How to merge 2 arrays based on their row indexD3 - 如何根据行索引合并 2 个数组
【发布时间】:2016-12-16 16:47:03
【问题描述】:

我正在使用 D3 进行可视化,需要根据行索引合并 2 个数组:

var links = 
[
{"source":"a0","target":"a0","s_portfolio":"a","t_portfolio":"a","SOURCE_TYPE":"APP","DES_TYPE":"APP"},
{"source":"a1","target":"a2","s_portfolio":"a","t_portfolio":"c","SOURCE_TYPE":"APP","DES_TYPE":"APP"},
{"source":"a1","target":"a2","s_portfolio":"a","t_portfolio":"c","SOURCE_TYPE":"APP","DES_TYPE":"APP"}  
];

var files =
[
{"File_Desc":"","DataName":""},
{"File_Desc":"Date","DataName":"Dates.01012016"},
{"File_Desc":"Address","DataName":"Address.01012016"}    
    ];

获得:

var result =
[
{"source":"a0","target":"a0","s_portfolio":"a","t_portfolio":"a","SOURCE_TYPE":"APP","DES_TYPE":"APP","File_Desc":"","DataName":""},
{"source":"a1","target":"a2","s_portfolio":"a","t_portfolio":"c","SOURCE_TYPE":"APP","DES_TYPE":"APP","File_Desc":"Date","DataName":"Dates.01012016"},
{"source":"a1","target":"a2","s_portfolio":"a","t_portfolio":"c","SOURCE_TYPE":"APP","DES_TYPE":"APP","File_Desc":"Address","DataName":"Address.01012016"}
]

【问题讨论】:

  • 如果这些是您将使用的数据,那么只需手动合并它们并删除问题。如果数据来自两个文件或数据源并且该数据非常大,那么手动处理比您需要脚本来处理更难。您可以利用经典的“for”循环,其中每个链接对应于每个结果,即一对一的关系。是否有一些具体要求没有说明?
  • @Vlad - 数据集包含在 1 个文件中,而且非常大。我正在研究力导向图,其中链接宽度基于连接数。当我尝试传递整个数组(不将其一分为二)时,我无法计算节点之间的连接数。
  • 任何类型的图实际上都是一种数据结构,因此您应该将其视为一种数据结构。图是包含节点和节点之间链接的结构。您可以使用邻接矩阵来解释哪个节点与哪个节点相连。当然,还可以为链接添加更多详细信息,也许还可以添加基于到一个节点的链接计算的链接权重?
  • @Vlad - 感谢您的反馈。我是 D3 和 JavaScript 的新手。但我肯定会研究邻接矩阵。
  • 幸运的是我正在修改这个力导向图bl.ocks.org/GerHobbelt/3104394,你可以在这里查看优化代码:github.com/bluePlayer/practices/tree/master/D3js%20Exercises/… 遗憾的是它是在 D3 版本 2 中制作的。

标签: javascript d3.js collections


【解决方案1】:

如果您可以使用后期模型 JavaScript(又名 ES2015), 最短路径是这样的:

var result = links.map((d,i) => Object.assign({}, d, files[i]));

这很短。它也不会修改linksfiles(如果您希望将它们与result 分开使用)。

附言

cmets 建议您关注替代解决方案的运行时间。一般来说,他们都很好,尤其是。作为 d3 应用程序中常见的一种一次性数据设置。但是,如果您有大型数据集或经常运行记录合并,那么您可能需要优化。

如果您愿意更新现有记录集而不是创建新记录集:

links.forEach((d,i) => Object.assign(d, files[i]));

在此之后,links 具有更新的记录。它的运行速度比其他解决方案快 7-10 倍,大概是因为它不会创建大量新对象。如果您完成了原始的、未合并的 linksfiles 对象,则没有特别的理由避免这种“破坏性”或“就地”更新。通常很少需要优化一次性设置操作。但是,如果您想或需要这样做,这是一种强大的方法。

【讨论】:

  • 谢谢!这很好用。与@dave 下面的建议有性能差异吗?
  • @Alexey 两者都在个位数毫秒内完成,但 dave 更快。如果您正在处理大型数据集或执行此操作数百或数千次,则增量可能很大。在大多数情况下,它不是。如果您只在数据初始化过程中执行此操作一次,则无关紧要。
【解决方案2】:

试试这个:

var links = [
  {"source":"a0","target":"a0","s_portfolio":"a","t_portfolio":"a","SOURCE_TYPE":"APP","DES_TYPE":"APP"},
  {"source":"a1","target":"a2","s_portfolio":"a","t_portfolio":"c","SOURCE_TYPE":"APP","DES_TYPE":"APP"},
  {"source":"a1","target":"a2","s_portfolio":"a","t_portfolio":"c","SOURCE_TYPE":"APP","DES_TYPE":"APP"}  
];

var files = [
  {"File_Desc":"","DataName":""},
  {"File_Desc":"Date","DataName":"Dates.01012016"},
  {"File_Desc":"Address","DataName":"Address.01012016"}    
];

var result = [];

for(let i = 0; i < links.length; i++){
  result[i] = Object.assign(links[i], files[i]);
}

console.log(result);

【讨论】:

  • 当我运行 console.log(result); File_Desc 和 DataName 到处都是空的。知道为什么吗?
  • @Alexey 你的result[0]["DataName"] === "" 所以它只会打印console.log(result[1]["DataName"]); 打印Dates.01012016。如果您的 console.log(result[1]["DataName"]); 打印了其他内容,则说明您的代码在其他地方有问题。
【解决方案3】:

我可能会使用array map 遍历一个数组,然后在我的回调函数中使用this answer 中定义的函数返回一个组合对象。

var result = links.map(combineLinkToFile);

function combineLinkToFile (link, index) {

    var file = files[index];

    return collect(link, file)
}

function collect() {
  var ret = {};
  var len = arguments.length;
  for (var i=0; i<len; i++) {
    for (p in arguments[i]) {
      if (arguments[i].hasOwnProperty(p)) {
        ret[p] = arguments[i][p];
      }
    }
  }
  return ret;
}

【讨论】:

  • 谢谢!这很好用。与上面@Jonathan Eunice 的建议有性能差异吗?
  • 我不知道性能差异。如果它对您很重要,可能最好自己测试一下。但是 Object.assign 对浏览器的支持比较有限,所以你可能不想将它用于前端。如果您能够使用 Object.assign,我更喜欢 Jonathan 的回答。
【解决方案4】:

使用 jQuery map() 和 extend() 方法:

function mergeObjectsInArrays(arr1, arr2){
    return $.map(arr1, function(el, i){
        return $.extend(el, arr2[i]);
    });
};

// then pass your arrays:
var result = mergeObjectsInArrays(links, files);

【讨论】:

  • OP 可能没有使用 jQuery。如果他不是,我认为没有理由介绍它。这可以在 vanilla JS 中轻松完成。
  • 感谢您提供见解,@dave。我很好奇为什么我的回答会被否决。
猜你喜欢
  • 2021-09-10
  • 1970-01-01
  • 2021-09-19
  • 2019-06-09
  • 2012-02-11
  • 1970-01-01
  • 2012-04-20
  • 2016-11-17
  • 1970-01-01
相关资源
最近更新 更多