相当于JavaScript中Ruby的each_cons

时间:2019-08-13 12:39:50

标签: javascript arrays ruby enumerator equivalent

这个问题已经问了很多语言,但不是javascript。

Ruby的方法Enumerable#each_cons如下所示:

puts (0..5).each_cons(2).to_a
# [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5]]
puts (0..5).each_cons(3).to_a
# [[1, 2, 3], [2, 3, 4], [3, 4, 5]]

如何在JavaScript中为Array使用类似的方法?

4 个答案:

答案 0 :(得分:4)

以下是可以执行此功能的功能(ES6 +):

// functional approach
const eachCons = (array, num) => {
    return Array.from({ length: array.length - num + 1 },
                      (_, i) => array.slice(i, i + num))
}

// prototype overriding approach
Array.prototype.eachCons = function(num) {
  return Array.from({ length: this.length - num + 1 },
                    (_, i) => this.slice(i, i + num))
}


const array = [0,1,2,3,4,5]
const log = data => console.log(JSON.stringify(data))

log(eachCons(array, 2))
log(eachCons(array, 3))

log(array.eachCons(2))
log(array.eachCons(3))

您必须猜测所得数组的长度(n = length - num + 1),然后才能利用JavaScript的array.slice来获取所需的块,并重复n次。 / p>

答案 1 :(得分:2)

您可以选择长度,构建一个新数组,然后使用Array.from和内置的映射器来映射切片的数组。

Number.prototype[Symbol.iterator] = function* () {
    for (var i = 0; i < this; i++) yield i;
};

Array.prototype.eachCons = function (n) {
    return Array.from({ length: this.length - n + 1}, (_, i) => this.slice(i, i + n));
}

console.log([...10].eachCons(2));
console.log([...10].eachCons(3));
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 2 :(得分:1)

这里是依赖函数生成器的单行解决方案。也许稍有不同,但仍然值得尝试。

我还添加了原型,不知道为什么要这么做,但仍然..

此解决方案不需要ES6,它也可以与ES5一起使用,但要注意一点一点,就是根本不支持函数生成器的IE。

function* eachCons(arr, num) {
  for (let counter = 0; counter <= arr.length - num; counter++) yield arr.slice(counter, counter + num);
}

Array.prototype.eachCons = function* (num) {
  for (let counter = 0; counter <= this.length - num; counter++) yield this.slice(counter, counter + num);
}

const array = [0,1,2,3,4,5];
const log = data => console.log(JSON.stringify(data))
log([...eachCons(array, 2)]);
log([...eachCons(array, 3)]);

// Iterable way
for (let [...pack] of eachCons(array, 2)) {
  console.log('pack is', pack);
}
// Prototype...
for (let [...pack] of array.eachCons(2)) {
  console.log('pack is', pack);
}

答案 3 :(得分:1)

使用looppush生成外观相似的输出的另一种(有点无聊)解决方案:

const array = [0,1,2,3,4,5]

const eachCons = (array, num) => {
    let cons = [];

    for (let i = 0; i < array.length - num + 1; i++) {
      cons.push(array.slice(i, i + num))
    }
    return cons;
}

console.log(eachCons(array, 3))

从IE9(?)开始应支持此功能,并且其性能应与某些功能方法相匹配甚至胜过某些功能。在我的FF60上,速度提高了50%:

const array = [0,1,2,3,4,5]

const funcCons = (array, num) => {
    return Array.from({ length: array.length - num + 1 },
                      (_, i) => array.slice(i, i + num))
}

const impCons = (array, num) => {
    let cons = [];

    for (let i = 0; i < array.length - num + 1; i++) {
      cons.push(array.slice(i, i + num))
    }
    return cons;
}

var t1 = performance.now();
for (let i = 0; i < 1000000; i++) {
  funcCons(array,3)
}
var t2 = performance.now();

var t3 = performance.now();
for (let i = 0; i < 1000000; i++) {
  impCons(array,3)
}
var t4 = performance.now();

console.log("functional time: " + (t2 - t1));
console.log("imperative time: " + (t4 - t3));

functional time: 499
imperative time: 331
@ 1.000.000 repetitions