Ellen Mina Kim
Ellen Mina Kim

Reputation: 71

Create array of objects based on length; each object has a property with the index + 1 as its value

I want to improve my ugly code to something more clean and simple. How can I shorten this code?

if (this.foo < 2) {
  return (this.result = [ { year: 1 } ]);
}
if (this.foo < 3) {
  return (this.result = [ { year: 1 }, { year: 2 } ]);
}
if (this.foo < 4) {
  return (this.result = [ { year: 1 }, { year: 2 }, { year: 3 } ]);
}
if (this.foo < 5) {
  return (this.result = [ { year: 1 }, { year: 2 }, { year: 3 }, { year: 4 } ]);
}
if (this.foo < 6) {
  return (this.result = [ { year: 1 }, { year: 2 }, { year: 3 }, { year: 4 }, { year: 5 } ]);
}

Upvotes: 0

Views: 1042

Answers (4)

Sebastian Simon
Sebastian Simon

Reputation: 19475

What you’ve shown is equivalent to this (except this goes beyond five elements, but also beyond one in the other direction):

return this.result = Array.from({
  length: Math.floor(this.foo)
}, (_value, index) => ({
  year: index + 1
}));

This assumes that this statement is inside a function (otherwise, return wouldn’t work).

A more reasonable length may be Math.max(0, Math.min(2 ** 32 - 1, Math.floor(this.foo))) which clamps1 the length to at least 0 and at most 232 − 1, the maximum Array length.

If you want to always have at least one element in your array, then use Math.max(1,) instead.

Returning an assignment (i.e. return this.result =;) is frowned upon. The best practice is to separate these statements2:

this.result = Array.from({
  length: Math.max(0, Math.min(2 ** 32 - 1, Math.floor(this.foo)))
}, (_value, index) => ({
  year: index + 1
}));

return this.result;

Array.from is used with both arguments: the first one is the “array-like” object { length: Math.max(0, Math.min(2 ** 32 - 1, Math.floor(this.foo))) } which gets converted to a proper Array object. In this case, an array with a length of Math.floor(this.foo) is initialized (clamped to the range of possible Array lengths). The second argument maps each value at a certain index to an object with the year property with the value index + 1. _value isn’t used (it’s undefined anyway).

The advantage to use Array.from(array-like,mapping-function) over e.g. .fill().map() is that only a single array is created in memory. Array().fill().map() creates two new arrays: the first one at Array().fill(), the second one at .map(). Therefore, the Array.from approach is more memory-efficient.


1: Maybe soon we’ll finally get a Math.clamp method…

2: Technically, this would be equivalent. If this.result is a getter / setter, there may be an observable difference.

const result = Array.from({
    length: Math.max(0, Math.min(2 ** 32 - 1, Math.floor(this.foo)))
  }, (_value, index) => ({
    year: index + 1
  }));

this.result = result;

return result;

Upvotes: 4

Aditya Joshi
Aditya Joshi

Reputation: 1053

try this oneliner

let x=3;
let result = [ ...Array(x).keys() ].map(item=> {return{"year":item}});
console.log(result);

Upvotes: 2

zmag
zmag

Reputation: 8241

Create an array with Array, and use Array.prototype.map.

function func(foo) {
  return Array(foo).fill().map((f, i) => ({ year: i + 1 }));
}

console.log(func(1));
console.log(func(3));

Upvotes: 7

Rajdeep D
Rajdeep D

Reputation: 3910

let arr = [];

for(let i = 1; i<this.foo;i++){ 
    arr.push({ 'year':i}) 
};

console.log(arr);

Upvotes: 1

Related Questions