如何在JavaScript中将一个数组拆分为数组对?

54

我想将一个数组拆分成数组对。

var arr = [2, 3, 4, 5, 6, 4, 3, 5, 5]

将会是

var newarr = [
    [2, 3],
    [4, 5],
    [6, 4],
    [3, 5],
    [5]
]

请参见 https://dev59.com/4Goy5IYBdhLWcg3wg-Ym - user1460043
16个回答

73

你可以使用js reduce

initialArray.reduce(function(result, value, index, array) {
  if (index % 2 === 0)
    result.push(array.slice(index, index + 2));
  return result;
}, []);

1
这里没有比这更短的了,最好的方法就是这样!(而且不需要额外的库) - chrismarx
请注意初始值 (即“[]”),这很容易被忽略。- https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce - chrismarx
3
你可以使用扩展运算符,几乎只需要一行代码 :D array.reduce((result, value, index, sourceArray) => index % 2 === 0 ? [...result, sourceArray.slice(index, index + 2)] : result, []) - mkbctrl

19

15

没有预设的函数可以完成这个任务,但是这里有一个简单的解决方案:

var splitPairs = function(arr) {
    var pairs = [];
    for (var i=0 ; i<arr.length ; i+=2) {
        if (arr[i+1] !== undefined) {
            pairs.push ([arr[i], arr[i+1]]);
        } else {
            pairs.push ([arr[i]]);
        }
    }
    return pairs;
};

OP显示的“arr”的长度是奇数怎么办? - jfriend00
好的,谢谢提醒。我已经修改了代码来处理这个情况。 - ChadF
你的第一个 push 语句好像缺少了一个闭合括号。 - vol7ron
以防万一有人在这里遇到了同样的问题:我之前使用for(var i = 0; i < arr.length; i + 2)导致进入了无限循环。由于i + 2并没有设置i的值,所以索引值没有更新。而使用i += 2可以设置i的值。这就是为什么尽可能地使用map/reduce函数式编程更好的原因! - larrydalmeida

13

这是另一篇有点混合了已经发布的答案。我添加它是因为阅读了这些答案后,我仍然觉得可以让读者更容易理解:

var groups = [];

for(var i = 0; i < arr.length; i += 2)
{
    groups.push(arr.slice(i, i + 2));
}

1
干得好,我觉得这个最容易理解了。 - Bemmu
很棒的解决方案。文档:slice:如果 end 大于序列的长度,则 slice 提取到序列的末尾(arr.length)。 - Gamma032
感谢您分享您的解决方案! - Amir Md Amiruzzaman
1
三年后,你正在帮助别人! - JaySnel

13

现在有了灵活的 Array#flatMap(value, index, array) 方法:

const pairs = arr.flatMap((_, i, a) => i % 2 ? [] : [a.slice(i, i + 2)]);

而可能更高效但看起来很奇怪的Array.from(source, mapfn?)

const pairs = Array.from({ length: arr.length / 2 }, (_, i) => arr.slice(i * 2, i * 2 + 2))

flatMap() 不仅是一种灵活的方式,而且是符合当今标准的最佳实践,应被视为最佳答案。 - ed1nh0

4

可以在不使用库的情况下,将数组分成一对/块:

function chunks(arr, size = 2) {
  return arr.map((x, i) => i % size == 0 && arr.slice(i, i + size)).filter(x => x)
}
console.log(chunks([1, 2, 3, 4, 5, 6, 7])) // -> [[1, 2], [3, 4], [5, 6], [7]]


3

这里有一个很好的通用解决方案:

function splitInto(array, size, inplace) {
    var output, i, group;

    if (inplace) {
        output = array;

        for (i = 0; i < array.length; i++) {
            group = array.splice(i, size);

            output.splice(i, 0, group);
        }
    } else {
        output = [];

        for (i = 0; i < array.length; i += size) {
            output.push(array.slice(i, size + i));
        }
    }

    return output;
}

对于您的情况,您可以这样调用:

var arr= [2,3,4,5,6,4,3,5,5];
var newarr = splitInto(arr, 2);
inplace参数决定操作是在原地进行还是不在原地进行。
下面是演示:

function splitInto(array, size, inplace) {
    var output, i, group;

    if (inplace) {
        output = array;

        for (i = 0; i < array.length; i++) {
            group = array.splice(i, size);

            output.splice(i, 0, group);
        }
    } else {
        output = [];

        for (i = 0; i < array.length; i += size) {
            output.push(array.slice(i, size + i));
        }
    }

    return output;
}

var arr= [2,3,4,5,6,4,3,5,5];
var newarr = splitInto(arr, 2);

disp(newarr);

// or we can do it in-place...
splitInto(arr, 3, true);

disp(arr);

function disp(array) {  
  var json = JSON.stringify(array);

  var text = document.createTextNode(json);
  var pre = document.createElement('pre');

  pre.appendChild(text);
  document.body.appendChild(pre);
}


3

与使用 for 循环进行比较略有不同的方法。为了避免修改原始数组,slice 创建一个浅拷贝,因为 JS 通过引用传递对象。

function pairArray(a) {
  var temp = a.slice();
  var arr = [];

  while (temp.length) {
    arr.push(temp.splice(0,2));
  }

  return arr;
}

var array = [2,3,4,5,6,4,3,5,5];
var newArr = pairArray(array);

function pairArray(a) {
  var temp = a.slice();
  var arr = [];

  while (temp.length) {
    arr.push(temp.splice(0,2));
  }

  return arr;
}

document.write('<pre>' + JSON.stringify(newArr) + '</pre>');


哈哈,我看到你喜欢不使用格式化,就像我一样 ;) - Patrick Roberts
@PatrickRobert 是的,在这种情况下,我意识到它使阅读变得更加困难。我想我们有相似的想法。 :) - Jason Cust

3
我会在这种情况下使用 lodash。以下是使用_.reduce的解决方案:
var newArr = _(arr).reduce(function(result, value, index) {
  if (index % 2 === 0)
    result.push(arr.slice(index, index + 2));

  return result;
}, []);

var arr = [2,3,4,5,6,4,3,5,5];

var newArr = _(arr).reduce(function(result, value, index) {
  if (index % 2 === 0)
    result.push(arr.slice(index, index + 2));
  
  return result;
}, []);

document.write(JSON.stringify(newArr)); // [[2,3],[4,5],[6,4],[3,5],[5]]
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.0/lodash.min.js"></script>


谢谢,lodash函数需要下载一个库吗? - Tormod Smith
是的,lodash是一个独立的库。您可以使用我在片段中使用的相同CDN。 - Mark T
Lodash不再需要,只适用于当前的观众:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce - Brandon
当使用lodash时,为什么要使用它的reduce()函数而不是直接使用chunk()函数(参见https://dev59.com/Ql0Z5IYBdhLWcg3whQsj#51264923)? - YetAnotherFrank

2

这里是使用lodash辅助函数的另一种解决方案:

function toPairs(array) {
  const evens = array.filter((o, i) => i % 2);
  const odds = array.filter((o, i) => !(i % 2));
  return _.zipWith(evens, odds, (e, o) => e ? [o, e] : [o]);
}
console.log(toPairs([2,3,4,5,6,4,3,5,5]));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.13.1/lodash.min.js"></script>


你可以在这里找到一个使用Immutable.js的类似示例:https://facebook.github.io/immutable-js/docs/#/List/zip - vcarel

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