Идиома для "повторить п раз"?
РЕДАКТИРОВАТЬ: голоса, чтобы закрыть неправильные. Принятый ответ в " Повторите символ N раз" в целом не применим. Например:
>>> Array(3).map(Math.random)
[undefined, undefined, undefined]
В двух других ответах предлагается изменить встроенный класс, что я считаю совершенно неприемлемым.
Вот один несколько расточительный и непрактичный способ создать массив из 3 случайных чисел в JS:
>>> [1, 1, 1].map(Math.random)
[0.6324464592887568, 0.5969209806782131, 0.7362755801487572]
Использование фиктивного массива (например, [1, 1, 1]
) просто чтобы можно было звонить map
на это, есть, для достаточно большого п как расточительный (из памяти), так и нецелесообразный.
То, что хотелось бы, было бы что-то вроде гипотетического:
>>> repeat(3, Math.random)
[0.21425955396598173, 0.00226050232425945, 0.45261888146445495]
Что ближе всего может прийти к этому в "чистом JS"?
(Я знаю о Underscore, но в его API есть вещи, которые не имеют смысла для меня, такие как интерпретация map
так что я пытаюсь этого избежать.)
7 ответов
Underscore.js имеет функцию times, которая делает именно то, что вы хотите:
_.times(3, Math.random)
Если вы не хотите использовать 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;
};
Это можно сделать с помощью Array.prototype.map
, но массив не может быть пустым. Заполните это сначала:
console.log(
Array(3).fill().map(Math.random)
);
Объяснение:
new Array(3)
Конструктор создает разреженный массив (или "дырявый" массив, как их называет команда V8) с тремя отверстиями в нем и длиной три. Это означает, что это эквивалентно [,,,]
, который создает [<empty>, <empty>, <empty>,]
(обратите внимание на конечные запятые в JavaScript).
Array.prototype.map
вызывается один раз для каждого элемента в массиве. Но поскольку пустой массив не имеет назначенных значений, обратный вызов вообще не вызывается. Например, [1,,2].map(v=>v*2)
даст [2,,4]
; средний слот пропущен.
Войти Array.prototype.fill(value, start?, end?)
: только с одним аргументом, он заполняет каждый слот в массиве указанным значением. Технически, первый параметр не является обязательным, но, опуская его, undefined
используется в качестве значения. Это нормально, потому что значение все равно не используется. Сюда Array(3).fill()
дает нам [undefined, undefined, undefined]
,
Теперь, когда в массиве есть значения, его можно отобразить, как показано выше.
Вы могли бы также spread
пустой array
в значения undefined
перед отображением:
console.log(
[...Array(3)].map(Math.random)
);
Объяснение:
Операторы массивов, представленные в ECMAScript2015 или более новые дыры угроз в массивах как undefined
ценности. Array.prototype.map
был введен в ES5 (IE, предшествовавший ES2015), где, как ни странно, дыры в массивах следует пропускать, создавая небольшую несогласованность в функциях JS Array в зависимости от того, в какой редакции ECMAScript они были выпущены.
Оператор спреда ...
был введен в ES2015, поэтому, согласно спецификации, он преобразует любые дыры в данном массиве в значения undefined
, Другими словами, [...Array(3)]
дает нам [undefined, undefined, undefined]
, как Array(3).fill()
делал выше.
Иногда вам может потребоваться посеять числа последовательно. Как отметил 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))
);
Самый короткий элегантный ES6:
let times=(n,f)=>{while(n-->0)f();}
о, это не для создания массива, но все равно аккуратно!
times(3,()=>print('wow'))
или Рубиновый стиль:
Object.assign(Number.prototype,{times(f){x=this;while(x-->0)f();}})
3..times(()=>print('wow'))
Может быть Array.from
обратный вызов может быть полезен:
var result = Array.from(Array(3), Math.random);
console.log(result);
Здесь есть небольшое преимущество перед использованием map
: map
уже нужен массив со всеми записями (может быть создан с fill
или синтаксис распространения), чтобы затем создать окончательный массив из этого. Итого map
Решение создаст n записей дважды. Array.from
не нужен массив с записями, просто объект с length
собственность будет делать, и Array(3)
обеспечивает это.
Таким образом, в зависимости от ваших предпочтений, вышеперечисленное также может быть сделано следующим образом:
var result = Array.from({length:3}, Math.random);
console.log(result);
Наконец, если бы вы создали repeat
Функция для этого, вы можете назвать аргумент length
и используйте краткую запись ES6 для литералов объектов:
const repeat = (length, cb) => Array.from({length}, cb);
const result = repeat(3, Math.random);
console.log(result);
Современный способ создать это repeat
функция:
repeat = (n, cb) => {[...Array(n)].forEach(cb)}
Затем вы можете использовать его с:
repeat(3, _ => console.log(Math.random()))
Будет вывод:
0.6324464592887568
0.5969209806782131
0.7362755801487572
Мне нравится этот способ:
[...Array(5).keys()].forEach(index =>
console.log(`do something ${index}`
)
Вы можете сделать следующее:
Iet res = 'n'.repeat(3).split('').map(Math.random)