Creating nested arrays of set structure
Creating nested arrays of set structure
I have an array of objects with named keys as follows:
Array1 [
'town1': 'London', // string
'town2': 'Paris', // string
'distance': 123456, // number
,
'town1': 'Seoul', // string
'town2': 'Tokio', // string
'distance': 654321, // number
,
,,... // Objects with same properties
]
Note that there might be objects without these keys. They should be skipped.
Having all this I want to create a new Array of arrays with 2 objects inside with the following rigid structure:
Array2 [
[ name: 'town1', value: 'distance', name: 'town2'],
[ name: 'town1', value: 'distance', name: 'town2'],
[..., ...], // All other objects with existing town1-town2-distance
]
How one could achieve it in the most efficient and fast way?
Thank you for your question! I know how to create a simple object name: 'town1', value: 'distance' by reducing or mapping forEach(a => ). But I can't figure out how to iterate 2 objects inside array inside another array...
– Igniter
Aug 25 at 14:22
Isn't the output supposed to be
[ name: 'London', value: 123456 , name: 'Paris' ]?– Aadit M Shah
Aug 25 at 14:27
[ name: 'London', value: 123456 , name: 'Paris' ]
Yep! And these values would vary depending on objects inside Array1.
– Igniter
Aug 25 at 14:29
4 Answers
4
Ok, I want to have my try as well! Why did nobody think about reduce? It's faster than for-loop! And more elegant. IMO at least.
So I've done few tests, and here are results:

And heres the code:
1) Array.prototype.reduce() with Array.prototype.push()
Array.prototype.reduce()
Array.prototype.push()
const array2 = array1.reduce((arr, obj) =>
if (obj.hasOwnProperty('town1') && obj.hasOwnProperty('town2') && obj.hasOwnProperty('value'))
arr.push([ name: obj.town1, value: obj.distance , name: obj.town2 ])
return arr
, )
2) Array.prototype.reduce() with Array.prototype.concat()
Array.prototype.reduce()
Array.prototype.concat()
const array2 = array1.reduce((arr, obj) => (
(obj.hasOwnProperty('town1') && obj.hasOwnProperty('town2') && obj.hasOwnProperty('value'))
? Array.prototype.concat(arr, [[ name: obj.town1, value: obj.distance , name: obj.town2 ]])
: arr
), )
3) Array.prototype.reduce() with spread operator
Array.prototype.reduce()
array2 = array1.reduce((arr, obj) => (
(obj.hasOwnProperty('town1') && obj.hasOwnProperty('town2') && obj.hasOwnProperty('value'))
? [...arr, [ name: obj.town1, value: obj.distance , name: obj.town2 ]]
: arr
), )
4) And @Emueeus go. For-loop with Array.prototype.push()
For-loop
Array.prototype.push()
for (let i = 0; i<array1.length; i++)
if (array1[i].hasOwnProperty('town1') && array1[i].hasOwnProperty('town2') && array1[i].hasOwnProperty('distance'))
array2.push([name:array1[i]['town1'], value: array1[i]['distance'], name: array1[i]['town2']])
Here's the test:
http://jsfiddle.net/4bca0g2u/
Thank you for your answer! Now that's confusing! I'm constantly getting various results using jsperf.com on your 4 tests. Looks like these tests are conducted on my machine, which is not very trustworthy, so there should be kind of remote-like services. If you know any online script measuring tools like Pingdom or Google Speed for websites, please share!
– Igniter
Aug 25 at 18:23
Here it is: jsperf.com/reduces-vs-for-loop. What do you use for testing performance?
– Igniter
Aug 25 at 18:25
@Igniter I wrote a quick performance test. Iterated each of those solutions 100k times, measured their performance with
performance.now() and divided the result by the iteration count. I've fired it on my local machine, you might be right, testing it on multiple environments would give a more trustworthy result. Here's the test through jsfiddle.net/4bca0g2u– Patryk Cieszkowski
Aug 25 at 19:52
performance.now()
I agree because you did one iteration, I'm not agree that it is more elegant. :)
– Emeeus
Aug 25 at 20:38
@Emeeus oh, you have every right to do so :) Although native functions seem to be more readable than for-loop. At least to me
– Patryk Cieszkowski
Aug 25 at 21:09
MinusFour's solution is almost correct. You'd also want to filter the elements which actually have the keys required:
Array2.filter(obj => obj.hasOwnProperty("town1") &&
obj.hasOwnProperty("town2") &&
obj.hasOwnProperty("distance"))
.map(obj => [ name: obj.town1, value: obj.distance , name: obj.town2 ]);
Is that what you're looking for?
Looks like a single map would work for you.
map
let mustHave = ['town1', 'town2', 'distance'];
Array1.filter(obj => mustHave.every(key => obj.hasOwnProperty(key))
.map(obj => [ name : obj.town1, value: obj.distance, name : obj.town2 ])
Edit: Didn't see that you didn't want to map objects without those keys. The filter takes care of that.
it would, but would throw undefined if any of those keys would be missing. OP wants those objects to be skipped
– Patryk Cieszkowski
Aug 25 at 14:30
@PatrykCieszkowski didn't see it, fixed.
– MinusFour
Aug 25 at 14:34
Just one iteration ( O(n) ) using for. It's faster than filter and map (2 iterations) see this https://jsperf.com/mapfiltervsfor/1
for
var array1 = [
'town1': 'London', // string
'town2': 'Paris', // string
'distance': 123456, // number
,
'town1': 'Seoul', // string
'town2': 'Tokio', // string
'distance': 654321, // number
];
var array2 = ;
for(let i = 0; i<array1.length; i++)
if(array1[i].hasOwnProperty('town1') && array1[i].hasOwnProperty('town2') && array1[i].hasOwnProperty('distance'))
array2.push([name:array1[i]['town1'], value: array1[i]['distance'], name: array1[i]['town2']])
console.log(array2)
First, interesting! That was unexpected I should say. Thank you for separate concerns about performance and the link to that site I didn't know about! I prefer this approach!
– Igniter
Aug 25 at 15:49
@Igniter Thanks, as a general rule (maybe not always), native methods like
.map .sort, .filter.. etc. are faster than plain for but sometimes those methods doesn't resolve the whole issue, and we have to use them more than once, in those cases is preferably in my opinion, to use for if we can resolve the issue with less iterations .– Emeeus
Aug 25 at 16:01
.map
.sort
.filter
for
for
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
What have you tried so far?
– Helping hand
Aug 25 at 14:14