简体   繁体   English

“重复n次”的成语?

[英]Idiom for "repeat n times"?

Here's a somewhat wasteful and impractical way to produce an array of 3 random numbers in JS:这是在 JS 中生成 3 个随机数数组的一种有点浪费和不切实际的方法:

[1, 1, 1].map(Math.random) // Outputs: [0.63244645928, 0.59692098067, 0.73627558014]

The use of a dummy array (eg [1, 1, 1] ), just so that one can call map on it, is -- for sufficiently large n -- both wasteful (of memory) and impractical.使用虚拟数组(例如[1, 1, 1] ),只是为了可以对其调用map ,对于足够大的n 来说,既浪费(内存)又不切实际。

What one would like, would be something like a hypothetical:人们想要什么,就像一个假设:

repeat(3, Math.random) // Outputs: [0.214259553965, 0.002260502324, 0.452618881464]

What's the closest we can do using vanilla JavaScript?我们可以使用 vanilla JavaScript 做的最接近的事情是什么?

I'm aware of libraries like Underscore, but I'm trying to avoid libraries here.我知道像 Underscore 这样的库,但我试图避免在这里使用库。

I looked at the answers to Repeat a string a number of times , but it is not applicable in general.我看了多次重复一个字符串的答案,但它通常不适用。 Eg:例如:

Array(3).map(Math.random) // Outputs: [undefined, undefined, undefined]
Array(4).join(Math.random()) // Outputs a concatenation of a repeated number
Array(3).fill(Math.random()) // Fills with the same number

Several other answers propose modifying a built-in class;其他几个答案建议修改内置类; a practice that I consider completely unacceptable.我认为完全不能接受的做法。

It can be done using Array.prototype.map , but the array can't be empty.可以使用Array.prototype.map来完成,但数组不能为空。 Fill it first: 先填写

 console.log( Array(3).fill().map(Math.random) );

Explanation:解释:

The new Array(3) constructor creates a sparse array (or "holey" array, as the V8 team calls them ) with three holes in it and a length of three . new Array(3)构造函数创建一个稀疏数组(或“holey”数组,正如 V8 团队所称的那样 其中包含三个孔,长度为 3 This means that it's equivalent to [,,,] , which creates [<empty>, <empty>, <empty>,] (note JavaScript's trailing commas ).这意味着它等同于[,,,] ,它创建[<empty>, <empty>, <empty>,] (注意 JavaScript 的尾随逗号)。 Note that an empty slot, ie a hole is not the same as undefined as an assigned value.请注意,空槽(即孔)与undefined为指定值不同。 undefined is an actual value, whereas <empty> is just a gap in the array. undefined是一个实际值,而<empty>只是数组中的一个间隙。

Array.prototype.map is called once for each element in the array . Array.prototype.map数组中的每个元素调用一次 But, because an empty array has no assigned values, the callback doesn't get called at all.但是,因为空数组没有赋值,所以根本不会调用回调。 For example, [1,,2].map(v=>v*2) would give [2,,4] ;例如, [1,,2].map(v=>v*2)会给出[2,,4] ; the middle slot is skipped, as it has a gap there.中间的插槽被跳过,因为它在那里有一个间隙。

Enter Array.prototype.fill(value, start?, end?) : with only one argument, it fills every slot in the array with the specified value.输入Array.prototype.fill(value, start?, end?) :只有一个参数,它用指定的值填充数组中的每个插槽。 Technically, the first parameter is not optional, but by omitting it, undefined is used as the value.从技术上讲,第一个参数不是可选的,但通过省略它, undefined用作值。 This is okay, because the value isn't being used anyway.这没关系,因为无论如何都不会使用该值。 This way Array(3).fill() gives us [undefined, undefined, undefined] .这样Array(3).fill()给了我们[undefined, undefined, undefined]

Now that the array has values in it, it can be mapped over, like seen above.现在数组中有值,它可以被映射,如上所示。


You could also spread the empty array into values of undefined before mapping:你也可以spreadarray到值的undefined映射之前:

 console.log( [...Array(3)].map(Math.random) );

Explanation:解释:

Array operators introduced in ECMAScript2015 or newer treat holes in arrays as undefined values . ECMAScript2015 或更新版本中引入的数组运算符将数组中的空洞视为undefined Array.prototype.map was introduced in ES5 (IE what preceded ES2015 ), where, confusingly, holes in arrays are to be skipped over, creating a little bit of inconsistency in JS Array functions depending on which edition of ECMAScript they were released in. Array.prototype.map是在 ES5(即 ES2015 之前的版本)中引入的,其中令人困惑的是,数组中的漏洞将被跳过,根据它们发布的 ECMAScript 版本,在 JS Array 函数中会产生一些不一致。

The spread operator ... was introduced in ES2015 , so as per spec, it converts any holes in the given array into values of undefined .扩展运算符... 是在 ES2015 中引入的,因此根据规范,它将给定数组中的任何空洞转换为undefined值。 In other words, [...Array(3)] gives us [undefined, undefined, undefined] , just like Array(3).fill() did above.换句话说, [...Array(3)]给了我们[undefined, undefined, undefined] ,就像上面的Array(3).fill()一样。


Sometimes you may need to seed in numbers sequentially.有时您可能需要按顺序播种。 As pointed out by Kevin Danikowski , Array.prototype.map gives you that out of the box, as the second parameter is the current key:正如Kevin Danikowski所指出的, Array.prototype.map为您提供了开箱即用的功能,因为第二个参数是当前键:

 const Fibonacci = n => Math.round(((5**.5 + 1) / 2)**n / 5**.5); console.log( Array(10).fill().map((_, i) => Fibonacci(++i)) );

Underscore.js has a times function that does exactly what you want: Underscore.js 有一个times函数,它完全符合你的要求:

_.times(3, Math.random)

If you don't want to use Underscore, you can just write your own times function (copied and slightly simplified from the Underscore source):如果您不想使用 Underscore,您可以编写自己的times函数(从 Underscore 源代码中复制并稍微简化):

times = function(n, iterator) {
  var accum = Array(Math.max(0, n));
  for (var i = 0; i < n; i++) accum[i] = iterator.call();
  return accum;
};

shortmost elegant ES6:最短的优雅 ES6:

let times=(n,f)=>{while(n-->0)f();}

oh, That's not for creating an array, but it's still neat!哦,那不是为了创建数组,但它仍然很整洁!

times(3,()=>print('wow'))

or Ruby style:或 Ruby 风格:

Object.assign(Number.prototype,{times(f){x=this;while(x-->0)f();}})
3..times(()=>print('wow'))

Maybe the Array.from callback can be of use:也许Array.from回调可以使用:

 var result = Array.from(Array(3), Math.random); console.log(result);

There is a slight advantage here over using map : map already needs an array with all the entries (maybe created with fill or the spread syntax), to then create the final array from that.与使用map相比,这里有一点优势: map已经需要一个包含所有条目的数组(可能使用fill或 spread 语法创建),然后从中创建最终数组。 So in total a map solution will create n entries twice .因此, map解决方案总共将创建n个条目两次 Array.from does not need an array with entries, just an object with a length property will do, and Array(3) is providing that. Array.from不需要带有条目的数组,只需一个具有length属性的对象即可,而Array(3)提供了这一点。

So depending on your preferences, the above can also be done like this:因此,根据您的喜好,也可以像这样完成上述操作:

 var result = Array.from({length:3}, Math.random); console.log(result);

Finally, if you would create a repeat function for this, you can name the argument length and use the ES6 short notation for object literals:最后,如果您要为此创建一个repeat函数,您可以命名参数length并使用 ES6 短表示法表示对象字面量:

 const repeat = (length, cb) => Array.from({length}, cb); const result = repeat(3, Math.random); console.log(result);

I like this way:我喜欢这种方式:

[...Array(5).keys()].forEach(index =>
  console.log(`do something ${index}`
)

A modern way to create that repeat function:创建repeat功能的现代方法:

repeat = (n, cb) => {[...Array(n)].forEach(cb)}

You can then use it with:然后您可以将其用于:

repeat(3, _ => console.log(Math.random()))

Would output:会输出:

0.6324464592887568
0.5969209806782131
0.7362755801487572

您可以执行以下操作:

'n'.repeat(3).split('').map(Math.random)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM