Reputation: 835
To return an array set
with a sequence of random numbers between 1 and 500 I tried to refactor a standard for loop for(var i = 0; i< 50; i++)
and that worked but when I tried to do a refactor using a for in
loop it doesn't. My guess is that there is something about the array.length
property and it's use that I'm screwing up.
TL;DR Why does this return an array of 50 undefined elements rather than an array of 50 random integers? And is there a way to make this approach work?
var set = [];
set.length = 50;
for(var i in set){
set[i] = Math.floor((Math.random() * 500) + 1);
}
console.log(set);
Similar Questions: Helpful but not quite what I'm looking for
As I suspected the point I was missing is that setting set.length
doesn't add elements to the array it only creates a sparse array (an array with gaps). In my case you cannot use for in
because there isn't anything in the array to iterate over. I would either have to populate the array with dummy content(i.e. empty strings) or, more logically, separate the range part I tried to implement with the .length
property into a separate range
variable.
Working version
var set = [], range = 50;
for(var i = 0; i < range; i++){
set[i]=Math.floor((Math.random() * 500) + 1);
}
console.log(set);
Upvotes: 5
Views: 27909
Reputation: 823
The best and easiest way to fill arrays is using filler values. This can be simply done by instantiating the Array()
class and useArray.protype.fill()
method to add value.
const array_filler = new Array(10).fill(20)
for further reference, you can read the following article
Upvotes: 0
Reputation: 3026
Old question but because I was looking for a short way to do this, I eventually came up with this method:
[...Array(50)].map(e => Math.floor((Math.random() * 500) + 1))
If you wanted to come up with a list of numbers from 1-50
, you can use the second argument of map:
[...Array(50)].map((e, i) => i + 1)
And finally, if you already have a function that returns a value, you can simply call that:
[...Array(50)].map(Math.random)
Upvotes: 1
Reputation: 8584
The issue is not with the array.length
property, it is that this method of enlarging the array does not create "properties." Note the following:
> [ /*hole*/ , /*hole*/ ,] // An array with two "holes"
[ , ]
> new Array(2) // Another way to create an array with two holes
[ , ]
> [ undefined, undefined ] // An array with two undefined elements -- not the same
[ undefined, undefined ]
> Object.getOwnPropertyNames([undefined, undefined]);
[ '0', '1', 'length' ]
> Object.getOwnPropertyNames([,,]);
[ 'length' ] // Doesn't have any integer properties!
What you're doing is creating an array with zero elements, then expanding it to include 50 "holes," like the array with two holes. Since this array has no enumerable properties (length
isn't enumerable), you can't iterate over it using for...in
. Ultimately, you would be better off using a traditional for
loop.
The best definition of a "hole" that I can come up with on the spot is a nonexistent property of an array whose name is an integer i
such that 0 <= i && i < array.length
. (In considering this, it is important to note that JavaScript arrays are just objects with numeric properties called "indices" and a few extra special features.)
There are two ways for a property reference to return undefined: either the property doesn't exist or the property exists and contains the value undefined. Thus:
> myObject = { myProp: 1, otherProp: undefined }
{ myProp: 1, otherProp: undefined }
> myObject.nonExistentProperty
undefined
> myObject.otherProp
undefined
Now, a hole is a nonexistent property, like myObject.nonExistentProperty
above, so trying to access it will cause it to return undefined
.
Upvotes: 2
Reputation: 265
It sounds to me like you want to create a static sized array with dynamic content. If this is the case, you need to create the array with the proper size first. That would create the array for you. However, you could auto-populate the array with the random values you wanted like so:
var N = 50;
var set = Array.apply(null, {length: N}).map(Function.call, Math.random);
Once the array is auto-populated, the rest of your code should work as expected, by simply using the value of the random number in the array so:
for(var i in set){
set[i] = Math.floor(set[i] * 500) + 1;
}
console.log(set);
// OUTPUT
// [267, 219, 293, 298, 403, 70, 162, 270, 434, 292, 433, 478, 476,
// 311, 268, 266, 105, 242, 255, 250, 206, 104, 142, 406, 50, 139,
// 364, 375, 47, 480, 445, 149, 91, 228, 404, 267, 298, 158, 305,
// 311, 92, 377, 490, 65, 149, 431, 28, 452, 353, 494]
This is where I got this: Create a JavaScript array containing 1...N
Upvotes: 5
Reputation: 93
The second link seems to have your answer.
The for (var item in array)
looks at your array and, for each item in the array, stores that item in "item" and lets you iterate over each item. Setting the array.length does not give you any items in the array, and thus the for in
does not execute at all - there is nothing to iterate over.
Upvotes: 1
Reputation: 16675
for in
does not seem like what you want here. Try a for
loop:
var set = [],
i = 0,
l = null;
set.length = 50;
for(; l = set.length; i < l; i++){
set[i] = Math.floor((Math.random() * 500) + 1);
}
console.log(set);
Upvotes: 2
Reputation: 26434
It returns undefined because you are setting the array length with set.length
. When this is called, all elements of the array are undefined
I'd remove the set.length
line altogether.
Updated code
var set = [];
for (i = 0; i <= 50; i++) {
set.push(Math.floor(Math.random() * 500))
}
console.log(set)
=> [138, 215, 149, 180, 348, 497, 88, 156, 238, 439, 130, 185, 20, 116, 330, 131, 188, 257,
260, 1, 469, 482, 208, 494, 26, 374, 281, 403, 403, 137, 156, 243, 378, 281, 329,
84, 471, 429, 120, 381, 456, 471, 36, 395, 299, 497, 151, 210, 80, 310]
Upvotes: 6