4

This is my code, acting upon myArray:

var myArray = [];
var i;

for(i = 0; i < 20; i += 1) {
   myArray.push(Math.random());
}

Is there a functional equivalent of the above that does without the dummy variable i?

Favorite answers:

  • while(myArray.push(Math.random()) < 20);
  • $.map(Array(20), Math.random);
  • for(var myArray = []; myArray.push(Math.random()) < 20;);
Randomblue
  • 112,777
  • 145
  • 353
  • 547
  • 6
    I don't think though. You can use "hacks" like `while(myArray.push(Math.random()) < 20);`. – Felix Kling Aug 04 '12 at 12:49
  • @FelixKling that does look a lot simpler than the for loop, and it can be debated if its really a hack :) – Vatev Aug 04 '12 at 12:52
  • @Vatev: Yeah well, it uses side effects which is not considered to be very clean and it's definitely not a functional approach. It's fun though :) Eventually you would put such code in a function anyway... – Felix Kling Aug 04 '12 at 12:54
  • @FelixKling: Using a `for`-loop, you could even inline the variable declaration :-) – Bergi Aug 04 '12 at 13:09
  • Try `Array.from({ length: 20 }, Math.random)` – Rajesh Aug 06 '18 at 13:29

5 Answers5

4

Not in ES5, there's no real functional equivalent to it, as you have to have something which has an amount of 20 to apply map to...

var my20ElementArray = [0,1,2,3,4,5,6,7,8,9,10];
var myArray = my20ElementArray.map(Math.random);

You could create an xrange-like function what is in Python but that would just hide this "unused" variable inside a function.

pimvdb
  • 151,816
  • 78
  • 307
  • 352
Aadaam
  • 3,579
  • 1
  • 14
  • 9
3

With JavaScript 1.7, you can use Array comprehensions for this task:

var myArray = [Math.random() for each (i in range(0, 20))];

However, with ES5.1 you can just use the Array constructor to generate an array of arbitrary length, and then map it to random numbers. Only drawback is that map() does not work with uninitialised values, so I first generate an Array of empty strings by using join and split:

var myArray = new Array(20).join(" ").split(" ").map(Math.random);

Ugly, but short. A maybe better (but less understandable) idea from Creating range in JavaScript - strange syntax:

var myArray = Array.apply(null, {length: 20}).map(Math.random);

Starting with @FelixKlings comment, one could also use this one-liner without the i loop variable:

for (var myArray=[]; myArray.push(Math.random()) < 20;);
// much better:
for (var myArray=[]; myArray.length < 20;) myArray.push(Math.random());
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • This will make all of the array elements the same random number. – Aadit M Shah Aug 04 '12 at 13:04
  • I didn't write in array comprehension, as it's an ES.next feature, and I expected the code to be run on today's platform's, but yeah, a nice solution :) – Aadaam Aug 04 '12 at 13:11
  • @AaditMShah: Which one? I don't think so. The [draft](http://wiki.ecmascript.org/doku.php?id=harmony:array_comprehensions) reads different, and I've tested the other two. – Bergi Aug 04 '12 at 13:17
  • @Bergi - My mistake. I expected `Math.random` to be invoked immediately. – Aadit M Shah Aug 04 '12 at 15:19
  • @AaditMShah If the comprehension syntax invoked `Math.random` immediately it would be pretty useless. A "normal" list comprehension would use an expression that refers to the loop variables, in order to compute a different item for each (combination of) loop variables. There's no point adding comprehension syntax to a language if the item expression is evaluated first and then simply repeated. – Ben Aug 06 '12 at 02:39
  • Array comprehensions seem not very reusable. They reveal their algorithms pretty much and rather are reminiscent of the imperative style. I wonder why they're considered functional. Why not better a recursive function as `fill = n => ctor => n === 0 ? [] : [new ctor].concat(fill(n - 1)(ctor));`. This works only with constructors though. It would have to be generalized to deal with any type. –  Apr 19 '16 at 15:47
  • @IvenMarquardt: Array comprehensions directly translate to `map`/`concatMap` in functional languages. They're just different syntax. – Bergi Apr 19 '16 at 16:08
  • Ah, merely syntactic sugar. Now it makes sense! –  Apr 19 '16 at 16:16
1

Are you looking for something as follows:

function makeArray(length, def) {
    var array = [];
    var funct = typeof def === "function";
    while (array.push(funct ? def() : def) < length);
    return array;
}

Then you can create arrays as follows:

var array = makeArray(100); // an array of 100 elements
var zero = makeArray(5, 0); // an array of 5 `0`s

In your case you may do something like:

var myArray = makeArray(20, Math.random);

See the following fiddle: http://jsfiddle.net/WxtkF/3/

Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299
1

how about this?

it's functionale style and it's very concise.

var makeRandomArray = function(n){
    if (n == 0) return [];
    return [Math.random()].concat(makeRandomArray(n-1));
};

console.log(makeRandomArray(20))

http://jsfiddle.net/YQqGP/

blueiur
  • 1,447
  • 1
  • 11
  • 17
0

You could try:

var myArray = String(Array(20)).split(',')
               .map( () => Math.random() );

Or extend the Array prototype with something like:

Array.prototype.vector = function(n,fn){
  fn = fn || function(){return '0';};
  while (n--){
    this.push(fn());
  }
  return this;
}
// usage
var myArray = [].vector(20, () => Math.random());

Or try something funny:

var myArray = function a(n,fn){
  return n ? a(n-1,fn).concat(fn()) : [];
}(20, () => Math.random())

Or use Array.from (ES>=2015)

Array.from({length: 20}).map(() => Math.random())
KooiInc
  • 119,216
  • 31
  • 141
  • 177