将数组分割成重叠的块(移动子组)

6

如何将JavaScript数组分成块是一个很好的问题。目前我正在写一些统计方法,我使用的答案如下(尽管我选择不像答案中那样扩展Array原型):

var chunk = function(array, chunkSize) {
    return [].concat.apply([],
        array.map(function(elem,i) {
            return i%chunkSize ? [] : [array.slice(i,i+chunkSize)];
        })
    );
};

这个函数接收一个数组,例如[1,2,3,4,5,6],并给定chunkSize为2,返回[[1,2],[3,4],[5,6]]。我想知道如何修改它以创建一个“重叠”的块数组(或对于熟悉移动平均值等方法的人来说,“移动子组”)。
如果提供与上面相同的数组和chunkSize为3,则会返回[[1,2,3],[2,3,4],[3,4,5],[4,5,6]]chunkSize为2将返回[[1,2],[2,3],[3,4],[4,5],[5,6]]
你有什么想法如何处理这个问题?
3个回答

6
function chunk (array, chunkSize) {
    var retArr = [];
    for (var i = 0; i < array.length - (chunkSize - 1); i++) {
        retArr.push(array.slice(i, i + chunkSize));
    }
    return retArr;
}

如果您想要扩展原型(这可能更好),它会像这样:
Array.prototype.chunk = function( chunkSize ) {
    var retArr = [];
    for (var i = 0; i < this.length - (chunkSize - 1); i++) {
        retArr.push( this.slice(i, i + chunkSize));
    }
    return retArr;
}

啊!是的。好发现(我使用块大小为2进行测试...)。再次感谢! - mbeasley
ES6版本:const movingSubgroups = ([...array], chunkSize = 2) => { chunkSize = Math.min(2 ** 32 - 1, Math.max(0, chunkSize)); return array.reduce((result, _element, index, currentArray) => { if(index <= currentArray.length - chunkSize){ result.push(currentArray.slice(index, index + chunkSize)); } return result; }, []); }; - Sebastian Simon
如果您要扩展内置原型或填充属性(即猴子补丁),请正确地执行:为了前向兼容性,请先检查属性是否存在,然后使属性不可枚举,以便构造对象的自有键不会被污染。对于方法,请使用_实际的_方法。我的建议是:遵循这些示例,演示如何添加一个行为与其他内置方法尽可能相似的方法。 - Sebastian Simon
@SebastianSimon 你是正确的。现在有更好的方法来做这件事。值得一提的是,当我在2013年写下这个答案时(8年前),你所建议的很多东西并没有得到完全支持。那时候,要么是因为我太菜了,要么是因为它本身并不成熟。这就是为什么它没有成为我的答案的一部分。在我看来,更好的建议是看看你在谷歌搜索答案时所找到的答案的年龄,并意识到随着时间的推移,事情会发生变化。 - gbtimmon
@gbtimmon 我完全知道这个答案的年龄。那个评论不是特定针对你的,而是针对任何将来考虑使用这个答案的读者。 - Sebastian Simon
显示剩余3条评论

0

使用更具声明性和简洁的方法(在我看来)。

const data = [1,2,3,4,5,6];

function getGroups(dataList, groupSize) {
  return dataList
    .slice(groupSize - 1)
    .map((_, index) => dataList.slice(index, index + groupSize));
}
console.log("2:", JSON.stringify(getGroups(data, 2)));
console.log("3:", JSON.stringify(getGroups(data, 3)));

首先,我从数组的开头删除元素的数量,因为输出的元素数量应该会适当变小。然后,我循环遍历剩余的元素,将它们映射到适当的组中。

-1

我对JavaScript不是很擅长,但使用两个嵌套的for循环算法上非常容易实现。这里提供了一个C#的解决方案 - 你应该能够很容易地理解它。

虽然使用的数据结构不是最优的,但算法本身是显而易见的。

protected List<List<int>> Split(List<int> array, int chunkSize)
{
    List<List<int>> result = new List<List<int>>();

    for (int i = 0; i < array.Count - chunkSize; i++)
    {
        List<int> temp = new List<int>();
        for (int j = i; j < i + chunkSize; j++)
        {
            temp.Add(array[j]);
        }
        result.Add(temp);
    }

    return result;
}

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