【问题标题】:More efficient/clever way to group/zip a multidimensional array in a particular manner以特定方式对多维数组进行分组/压缩的更有效/更聪明的方法
【发布时间】:2017-09-23 05:20:18
【问题描述】:

我有一个多维数组,我不知道它的大小,我所知道的是每个孩子都有相同的长度和相同的结构。

我需要将第一个孩子的内部数组与其兄弟的内部数组连接起来,以便所有具有相同索引的子内部数组都在一个数组中。

(如果有人想更好地表达它,或者改进标题,请做我的客人)

示例:

let arrays = [

    //1
    [[1, 2], [3, 4], [5, 6]],

    //2
    [[10, 20], [30, 40], [50, 60]],

    //3
    [[100, 200], [300, 400], [500, 600]],

    //N
    [[10000, 20000], [30000, 40000], [50000, 60000]],

];

预期结果:

[
    [1, 2, 10, 20, 100, 200, 10000, 20000],
    [3, 4, 30, 40, 300, 400, 30000, 40000],
    [5, 6, 50, 60, 500, 600, 50000, 60000]
]

这是我目前正在做的事情,它正在工作,但它有点矫枉过正。

/**
*   Helper function
*   Will return all the values at ${index} of each array in ${arrays}
*   Example: index(1, [[1,2], [3,4]]); //[2, 4]
*/

function index(index, arrays){

    let results = [];

    for(let i = 0, len = arrays.length; i < len; i++)
        results.push(arrays[i][index]);

    return results;
}

let first = arrays.shift();    
let output = first.map((item, i) => item.concat( ...index(i, arrays) ))

我正在寻找一种更有效的方法来做到这一点,因为它在节点服务器中运行,而且也是一种更聪明的方法(不一定要更有效)。

注意:我使用的是node v7.8.0,所以可以使用ES6。

更新:

展开运算符比apply慢很多

所以我的代码这样更快:

return first.map((item, i) => [].concat.apply(item, index(i, clone) ));

JSPERF:

我测试了jsperf 中的所有答案,@ibrahimMahrir 的方式显然是最快的。

/**
*   Will return all the values at ${index} of each array in ${arrays}
*   Example: index(1, [[1,2], [3,4]]); //[2, 4]
*/

function index(index, arrays){

    let results = [];

    for(let i = 0, len = arrays.length; i < len; i++)
        results.push(arrays[i][index]);

    return results;
}

let arrays = [

	//1
	[[1, 2], [3, 4], [5, 6]],

	//2
	[[10, 20], [30, 40], [50, 60]],

	//3
	[[100, 200], [300, 400], [500, 600]],

	//N
	[[10000, 20000], [30000, 40000], [50000, 60000]],

];

let first = arrays.shift();
let output = first.map((item, i) => item.concat( ...index(i, arrays) ));

console.log(output);

【问题讨论】:

  • 子数组的长度都一样吗?
  • @ibrahimmahrir 是的,他们有,唯一不同的是他们拥有的价值观。

标签: javascript arrays node.js performance multidimensional-array


【解决方案1】:

这是一个典型的映射减少工作。你可以这样做;

var arrs = [[[1, 2], [3, 4], [5, 6]], [[10, 20], [30, 40], [50, 60]], [[100, 200], [300, 400], [500, 600]], [[10000, 20000], [30000, 40000], [50000, 60000]]],
    res  = arrs.reduce((p,c) => p.map((s,i) => s.concat(c[i])));
console.log(res);

【讨论】:

  • OP 正在寻求性能增强,因此使用 reduce 和其他类似功能的成本会很高。
  • @Marcos Casagrande 您可以通过将上述 sn-p 改写为命令式风格来提高其性能。然后它会以更丑的外观为代价运行得更快一点:)
  • @Redu 我也想要一个聪明的方法,这真的比我现在的方法更优雅。我不得不承认,这里已经很晚了,我已经工作了 12 个小时,我的心态想不出更好的方法:P
【解决方案2】:

使用reduce 及其姐妹会以性能为代价。使用基本的for 循环并不是最漂亮的,但肯定更快。

function group(arrays){

    let results = [],
        len = arrays.length;

    if(!len) return results; // if this line is not necessary then remove it

    let i, j, k,
        innerLen = arrays[0].length;

    for(j = 0; j < innerLen; j++) {
        let arr = [];
        for(i = 0; i < len; i++)
            for(k = 0; k < arrays[i][j].length; k++) // assuming the last level of arrays could be of different lengths
                arr.push(arrays[i][j][k]);
        results.push(arr);
    }

    return results;
}

let arrays = [[[1,2],[3,4],[5,6]],[[10,20],[30,40],[50,60]],[[100,200],[300,400],[500,600]],[[10000,20000],[30000,40000],[50000,60000]]];
console.log(group(arrays));

【讨论】:

  • 谢谢!这是目前最快的方法。只是一个小细节,参数index 未使用且不需要:)
  • @MarcosCasagrande 哎呀!是的!我删除了它。
  • 我之前给出的基准被污染了,所以这里有一个新的,我包括一个 jsperf(顺便说一句,它产生的结果与我在节点中得到的结果完全不同)。
  • zip-map-flatten: 4055.662ms my-way: 2565.685ms reduce: 2772.728ms group: 232.283ms zip-flatten: 4201.483ms zip-flatten2: 3538.064ms jsperf.com/zip-group-multidimensional-array
  • 顺便说一句,传播运算符在我的方法中是多余的。删除它,它需要一半的时间。
【解决方案3】:

这是我对可读方法的尝试,基于使用 zipflatten 实用方法分解操作:

let arrays = [
    //1
    [[1, 2], [3, 4], [5, 6]],
    //2
    [[10, 20], [30, 40], [50, 60]],
    //3
    [[100, 200], [300, 400], [500, 600]],
    //N
    [[10000, 20000], [30000, 40000], [50000, 60000]],
]

// from http://stackoverflow.com/a/10284006/7256039
const zip = a => a[0].map((_,i) => a.map(e => e[i]))

const flatten = a => [].concat(...a)

let result = zip(arrays).map(flatten)

console.log(result)
.as-console-wrapper { min-height: 100%; }

这是我能想到的最快的内联/for-loop 版本,同时又不会牺牲太多的可读性:

let arrays = [
    //1
    [[1, 2], [3, 4], [5, 6]],
    //2
    [[10, 20], [30, 40], [50, 60]],
    //3
    [[100, 200], [300, 400], [500, 600]],
    //N
    [[10000, 20000], [30000, 40000], [50000, 60000]],
]

function zipMapFlatten (a) {
  const result = [], rows = a.length, cols = a[0].length
  let i, j, e
  for (j = 0; j < cols; j++) {
    result.push(e = [])
    for (i = 0; i < rows; i++) e.push.apply(e, a[i][j])
  }
  return result
}

let result = zipMapFlatten(arrays)

console.log(result)
.as-console-wrapper { min-height: 100%; }

【讨论】:

  • 一点也不差!你帮我找到了我想做的“正确”术语。
猜你喜欢
  • 2016-07-24
  • 1970-01-01
  • 2019-05-31
  • 1970-01-01
  • 1970-01-01
  • 2022-01-18
相关资源
最近更新 更多