do <something> N times (declarative syntax)
JavascriptJqueryunderscore.jsJavascript Problem Overview
Is there a way in Javascript to write something like this easily:
[1,2,3].times do {
something();
}
Any library that might support some similar syntax maybe?
Update: to clarify - I would like something()
to be called 1,2 and 3 times respectively for each array element iteration
Javascript Solutions
Solution 1 - Javascript
Just use a for
loop:
var times = 10;
for(var i = 0; i < times; i++){
doSomething();
}
Solution 2 - Javascript
Possible ES6 alternative.
Array.from(Array(3)).forEach((x, i) => {
something();
});
And, if you want it "to be called 1,2 and 3 times respectively".
Array.from(Array(3)).forEach((x, i) => {
Array.from(Array(i+1)).forEach((x, i2) => {
console.log(`Something ${ i } ${ i2 }`)
});
});
Update:
Taken from filling-arrays-with-undefined
This seems to be a more optimised way of creating the initial array, I've also updated this to use the second parameter map function suggested by @felix-eve.
Array.from({ length: 3 }, (x, i) => {
something();
});
Solution 3 - Javascript
This answer is based on Array.forEach
, without any library, just native vanilla.
To basically call something()
3 times, use:
[1,2,3].forEach(function(i) {
something();
});
considering the following function:
function something(){ console.log('something') }
The output will be:
something
something
something
To complete this questions, here's a way to do call something()
1, 2 and 3 times respectively:
It's 2017, you may use ES6:
[1,2,3].forEach(i => Array(i).fill(i).forEach(_ => {
something()
}))
or in good old ES5:
[1,2,3].forEach(function(i) {
Array(i).fill(i).forEach(function() {
something()
})
}))
In both cases, the output will be
The output will be:
something
something
something
something
something
something
(once, then twice, then 3 times)
Solution 4 - Javascript
fill
all items with undefined
before using map
:
Create an Array and Read detailed reason why map
is skipping never-defined array items
⚠️ Array.fill
has no IE support
Array(5).fill().map((item, i) => console.log(item, i))
Or fill do the same as above without fill, by destructuring the Array, which automatically sets undefined
for each item, if the item's value was not set:
[...Array(5)].map((item, i) => console.log(item, i))
If you want to make the above more "declarative", my currently opinion-based solution would be:
const iterate = times => callback => [...Array(times)].map((n,i) => callback(i))
iterate(3)(console.log)
Using old-school (reverse) loop:
// run 5 times: for( let i=5; i--; ) console.log(i)
Or as a declarative "while":
const run = (cb, ...args) => count => { while(count--) cb(...args) }
// executes the callback with whatever arguments, 3 times
run(console.log, 1,2,3)(3)
Solution 5 - Javascript
With lodash:
_.each([1, 2, 3], (item) => {
doSomeThing(item);
});
//Or:
_.each([1, 2, 3], doSomeThing);
Or if you want to do something N times:
const N = 10;
_.times(N, () => {
doSomeThing();
});
//Or shorter:
_.times(N, doSomeThing);
Solution 6 - Javascript
Since you mention Underscore:
Assuming f
is the function you want to call:
_.each([1,2,3], function (n) { _.times(n, f) });
will do the trick. For example, with f = function (x) { console.log(x); }
, you will get on your console:
0 0 1 0 1 2
Solution 7 - Javascript
You can also do the same thing with destructuring as follows
[...Array(3)].forEach( _ => console.log('do something'));
or if you need index
[...Array(3)].forEach(( _, index) => console.log('do something'));
Solution 8 - Javascript
If you can't use Underscorejs, you can implement it yourself. By attaching new methods to the Number and String prototypes, you could do it like this (using ES6 arrow functions):
// With String
"5".times( (i) => console.log("number "+i) );
// With number variable
var five = 5;
five.times( (i) => console.log("number "+i) );
// With number literal (parentheses required)
(5).times( (i) => console.log("number "+i) );
You simply have to create a function expression (of whatever name) and assign it to whatever property name (on the prototypes) you would like to access it as:
var timesFunction = function(callback) {
if (typeof callback !== "function" ) {
throw new TypeError("Callback is not a function");
} else if( isNaN(parseInt(Number(this.valueOf()))) ) {
throw new TypeError("Object is not a valid number");
}
for (var i = 0; i < Number(this.valueOf()); i++) {
callback(i);
}
};
String.prototype.times = timesFunction;
Number.prototype.times = timesFunction;
Solution 9 - Javascript
How about a simple while.
let times = 5;
while (times--) {
console.log(times+1)
}
References on how this works: Falsy and Decrement (--)
Solution 10 - Javascript
Just use a nested loop (maybe enclosed in a function)
function times( fct, times ) {
for( var i=0; i<times.length; ++i ) {
for( var j=0; j<times[i]; ++j ) {
fct();
}
}
}
Then just call it like this:
times( doSomething, [1,2,3] );
Solution 11 - Javascript
times = function () {
var length = arguments.length;
for (var i = 0; i < length ; i++) {
for (var j = 0; j < arguments[i]; j++) {
dosomthing();
}
}
}
You can call it like this:
times(3,4);
times(1,2,3,4);
times(1,3,5,7,9);
Solution 12 - Javascript
const loop (fn, times) => {
if (!times) { return }
fn()
loop(fn, times - 1)
}
loop(something, 3)
Solution 13 - Javascript
Array.from (ES6)
function doSomthing() {
...
}
Use it like so:
Array.from(Array(length).keys()).forEach(doSomthing);
Or
Array.from({ length }, (v, i) => i).forEach(doSomthing);
Or
// array start counting from 1
Array.from({ length }, (v, i) => ++i).forEach(doSomthing);
Solution 14 - Javascript
There is a fantastic library called Ramda, which is similar to Underscore and Lodash, but is more powerful.
const R = require('ramda');
R.call(R.times(() => {
console.log('do something')
}), 5);
Ramda contains plenty of useful functions. See Ramda documentation
Solution 15 - Javascript
var times = [1,2,3];
for(var i = 0; i < times.length; i++) {
for(var j = 0; j < times[i];j++) {
// do something
}
}
Using jQuery .each()
$([1,2,3]).each(function(i, val) {
for(var j = 0; j < val;j++) {
// do something
}
});
OR
var x = [1,2,3];
$(x).each(function(i, val) {
for(var j = 0; j < val;j++) {
// do something
}
});
#EDIT You can do like below with pure JS:
var times = [1,2,3];
times.forEach(function(i) {
// do something
});
Solution 16 - Javascript
you can use
Array.forEach
example:
function logArrayElements(element, index, array) {
console.log("a[" + index + "] = " + element);
}
[2, 5, 9].forEach(logArrayElements)
or with jQuery
$.each([52, 97], function(index, value) {
alert(index + ': ' + value);
});
Solution 17 - Javascript
// calls doSomething 42 times
Array( 42 ).join( "x" ).split( "" ).forEach( doSomething );
and
// creates 42 somethings
var somethings = Array( 42 ).join( "x" ).split( "" ).map( () => buildSomething(); );
or ( via https://stackoverflow.com/a/20066663/275501 )
Array.apply(null, {length: 42}).forEach( doSomething );
Solution 18 - Javascript
These answers are all good and well and IMO @Andreas is the best, but many times in JS we have to do things asynchronously, in that case, async has you covered:
http://caolan.github.io/async/docs.html#times
const async = require('async');
async.times(5, function(n, next) {
createUser(n, function(err, user) {
next(err, user);
});
}, function(err, users) {
// we should now have 5 users
});
These 'times' features arent very useful for most application code, but should be useful for testing.
Solution 19 - Javascript
Assuming we can use some ES6 syntax like the spread operator, we'll want to do something as many times as the sum of all numbers in the collection.
In this case if times is equal to [1,2,3]
, the total number of times will be 6, i.e. 1+2+3.
/**
* @param {number[]} times
* @param {cb} function
*/
function doTimes(times, cb) {
// Get the sum of all the times
const totalTimes = times.reduce((acc, time) => acc + time);
// Call the callback as many times as the sum
[...Array(totalTimes)].map(cb);
}
doTimes([1,2,3], () => console.log('something'));
// => Prints 'something' 6 times
This post should be helpful if the logic behind constructing and spreading an array isn't apparent.
Solution 20 - Javascript
Given a function something
:
function something() { console.log("did something") }
And a new method times
added to the Array
prototype:
Array.prototype.times = function(f){
for(v of this)
for(var _ of Array(v))
f();
}
This code:
[1,2,3].times(something)
Outputs this:
did something
did something
did something
did something
did something
did something
Which I think answers your updated question (5 years later) but I wonder how useful it is to have this work on an array? Wouldn't the effect be the same as calling [6].times(something)
, which in turn could be written as:
for(_ of Array(6)) something();
(although the use of _
as a junk variable will probably clobber lodash or underscore if you're using it)
Solution 21 - Javascript
Using Array.from
and .forEach
.
let length = 5;
Array.from({length}).forEach((v, i) => {
console.log(`#${i}`);
});
Solution 22 - Javascript
TypeScript Implementation:
For those of you who are interested in how to implement String.times
and Number.times
in a way that is type safe and works with the thisArg
, here ya go:
declare global {
interface Number {
times: (callbackFn: (iteration: number) => void, thisArg?: any) => void;
}
interface String {
times: (callbackFn: (iteration: number) => void, thisArg?: any) => void;
}
}
Number.prototype.times = function (callbackFn, thisArg) {
const num = this.valueOf()
if (typeof callbackFn !== "function" ) {
throw new TypeError("callbackFn is not a function")
}
if (num < 0) {
throw new RangeError('Must not be negative')
}
if (!isFinite(num)) {
throw new RangeError('Must be Finite')
}
if (isNaN(num)) {
throw new RangeError('Must not be NaN')
}
[...Array(num)].forEach((_, i) => callbackFn.bind(thisArg, i + 1)())
// Other elegant solutions
// new Array<null>(num).fill(null).forEach(() => {})
// Array.from({length: num}).forEach(() => {})
}
String.prototype.times = function (callbackFn, thisArg) {
let num = parseInt(this.valueOf())
if (typeof callbackFn !== "function" ) {
throw new TypeError("callbackFn is not a function")
}
if (num < 0) {
throw new RangeError('Must not be negative')
}
if (!isFinite(num)) {
throw new RangeError('Must be Finite')
}
// num is NaN if `this` is an empty string
if (isNaN(num)) {
num = 0
}
[...Array(num)].forEach((_, i) => callbackFn.bind(thisArg, i + 1)())
// Other elegant solutions
// new Array<null>(num).fill(null).forEach(() => {})
// Array.from({length: num}).forEach(() => {})
}
A link to the TypeScript Playground with some examples can be found here
This post implements solutions posted by: Andreas Bergström, vinyll, Ozay Duman, & SeregPie
Solution 23 - Javascript
Just thought I'd add, there is a nifty JS method called .repeat(n)
which will repeat a string 'n' number of times. So if you're looking for something to repeat a string 'n' number of times...
function repeatString (number, string) {
return string.repeat(number);
}
So if you did...
repeatString(3, 'Hey there! ');
You'd get: 'Hey there! Hey there! Hey there! '