【问题标题】:How do I create a collection of arrays from a single array?如何从单个数组创建数组集合?
【发布时间】:2013-05-26 08:36:51
【问题描述】:

假设我有一个像这样的大数组

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]

并希望将其拆分为一个 n 元组数组,例如

[[1,2], [3,4], [5,6], [7,8], [9,10], [11,12], [13,14] /*, ... */ ] // (for n=2)

有没有一些简单的方法来实现这一点?特例 n = 2 对我来说就足够了。

【问题讨论】:

  • 你试过什么?你在哪里遇到麻烦?完成这件事你有什么不明白的地方?
  • 只需为此编写一些javascript 代码,进行一些迭代。
  • @Andy 对于“初学者”问题,您无需避免 SO。问题很可能是,如果没有表现出努力,就好像您只是在要求某人为您完成工作。这可能不是你的意图,但不是很清楚。
  • @Andy:FWIW,在我看来,删除你的underscorejs 标签的人是完全不合适的。我冒昧地将其添加回来。当然,解决方案可能不需要它,但这并不意味着如果 Underscore 有一些有用的东西,它就不能使用。包含它是正确的,以表明需要下划线的解决方案是可以接受的。
  • @T.J.Crowder 不管怎样,我学到了宝贵的一课,像你这样的成员让它变得很棒。感谢您抽出宝贵时间做出回应,我什至已将解决方案提交给 lodash 以供考虑,因为它真的很聪明而且很棒。很高兴从中产生了一些有用的东西!我会确保将来更清楚

标签: javascript arrays underscore.js


【解决方案1】:

这应该可行:

for (var i=0; i<arr.length; i+=2) {
  result.push([arr[i], arr[i+1]]);
}

想出了这个,它应该适用于任意数量的“口袋”或任何你想称呼它们的东西。它检查undefined,因此它适用于奇数个项目:

Array.prototype.pockets = function(n) {

  var result = [],
      pocket = [],
      i, j;

  for (i=0; i<this.length; i+=n) {
    pocket.length = 0;
    for (j=1; j<n; j++) if (this[i+j] != null) pocket.push(this[i+j]);
    result.push([this[i]].concat(pocket));
  }

  if (arguments.length > 1) {
    return result.pockets.apply(result, [].slice.call(arguments,1));
  }

  return result;
};

// Usage:
var arr = [1,2,3,4,5,6,7,8,9,10,11];

arr.pockets(2); //=> [[1,2],[3,4],[5,6],[7,8],[9,10],[11]]
arr.pockets(3); //=> [[1,2,3],[4,5,6],[7,8,9],[10,11]]

// Recursive:
arr.pockets(1,3); //=> [ [[1],[2],[3]], [[4],[5],[6]], [[7],[8],[9]], [[10],[11]] ]

【讨论】:

  • 那里有逻辑错误。如果你在循环中使用i+=2,可能不想要++i。
  • @elclanrs:好吧,我不会这样做(对于以后维护它的人来说太混乱了,不必要的存储操作),但是是的,它应该可以工作。
  • @T.J.Crowder - 你能提供改进的解决方案吗?任何下划线函数都可以提供帮助
  • @Andy:我不知道下划线,但是当我看到这个问题时,我确实浏览了文档,并且没有立即看到任何可以做得更多的东西比这个解决方案更简单。我的更改将是 edit:将是 elclanrs 刚刚发布的第二个解决方案。
  • 是的,我只是发布了一个快速解决方案,但同时得到了两个想法并且搞定了,哈哈。我发布了i+=2 替代方案。
【解决方案2】:

使用Array.slice 可以更简单地做到这一点:

function grouper(lst, size) {
    var result = [], i=0, n=lst.length;
    while(i < n) {
        result.push(lst.slice(i, i+size));
        i += size;
    }
    return result
}

效率也更高:http://jsperf.com/grouper

【讨论】:

  • 我最喜欢这个。不过我会使用for 而不是while。
  • 这比我的解决方案要好。好的 JSPerf。
  • 如果有人想要的话,这是我根据这个答案保存的要点:gist.github.com/elclanrs/5652418
【解决方案3】:

对于下划线变体,您可以使用_.groupBy() 实现此目的,按项目的索引分组:

var doubles = _.groupBy(singles, function (num, i) {
    return Math.floor(i / 2);
});

不过,由于_.groupBy() 返回一个Object,因此获得一个Array 需要一些额外的工作:

_.mixin({
    segment: function (coll, per) {
        var result = [];
        _.chain(coll)
            .groupBy(function (item, i) { return Math.floor(i / per)})
            .each(function (group, key) { result[key] = group; })
        return result;
    }
});

var singles = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18];

var doubles = _.segment(singles, 2);
var triples = _.segment(singles, 3);

【讨论】:

  • 很好的解决方案,并且很容易扩展到 n 组。一个警告:它依赖于对象的迭代顺序,这被证明是任意的,但实际上所有已知的浏览器都是顺序的。
【解决方案4】:

在 python 中,这可以通过zip(*[iter(xs)]*n) 完成。只是为了好玩,这是一个 JS 实现:

让我们从一个穷人的生成器开始(在 ES6 传播之前,这就是我们所拥有的):

StopIteration = {"name": "StopIteration"}

function iter(xs) {
    if('next' in xs)
        return xs;
    var i = 0;
    return {
        next: function() {
            if(i >= xs.length)
                throw StopIteration;
            return xs[i++];
        }
    }
}

next = function(it) { return it.next() }

zip() 微不足道:

zip = function() {
    var args = [].map.call(arguments, iter), chunks = [];
    while(1) {
        try {
            chunks.push(args.map(next));
        } catch(StopIteration) {
            return chunks;
        }
    }
}

现在,要创建链对,只需将相同的迭代两次传递给 zip:

xs = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

it = iter(xs)
a = zip(it, it)

console.log(a)
// [[1,2],[3,4],[5,6],[7,8],[9,10],[11,12]]

对于 N 对,需要额外的实用程序:

repeat = function(x, n) {
    for(var a = []; n; n--)
        a.push(x);
    return a;
}

a = zip.apply(this, repeat(iter(xs), 5))

console.log(a) 
// [[1,2,3,4,5],[6,7,8,9,10]]

请注意,就像在 Python 中一样,这会去除不完整的块。

【讨论】:

    猜你喜欢
    • 2022-01-20
    • 1970-01-01
    • 2020-08-03
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 2022-12-02
    • 1970-01-01
    • 2014-09-25
    相关资源
    最近更新 更多