Iterating nested object in JavaScript withoud jQuery - javascript

I'm trying to iterate through a nested object.
array=[
{
id: 2,
items: [
{
id: 12
},
{
id: 13
},
{
id: 14
}
]
},
{
id: 3,
items: [
{
id: 15
},
{
id: 16
},
{
id: 17
},
{
id: 18
},
{
id: 19
}
]
},
{
id: 4,
items: [
{
id: 20
},
{
id: 21
}
]
},
{
id: 5,
items: [
{
id: 22
}
]
}
];
I need to push all the ID into one array in order that we can see in the code above. Something like this:
arrayOfId = [2, 12, 13, 14, 3, 15, 16, 17, 18, 19, 4, 20, 21, 5, 22];
I tried to do it by myself and found some examples here, but they are based on jQuery. I use Angular in my project.
Maybe someone knows solution of this issue with plain JS or Angular?
Thanks a lot.

It's actually very simple.
get the length of the array.
loop through the array and push a new array (ids) with the current id value.
get the length of the nested array.
loop through that and push the nested ids also in that array.
var l=array.length,i=0,ids=[];
for(;i<l;i++){
ids.push(array[i].id);
var nested=array[i].items,nl=nested.length,j=0;
for(;j<nl;ids.push(nested[j++].id));
};
console.log(ids);
alert(ids);
//ids=[2,12,13,14,3,15,16,17,18,19,4,20,21,5,22];
In this example i show various ways to write the for loop.
Also by caching the length and other variables like the nested array, the performance is increased. I also like to mention, that for simple functions like this, where you have to LOOP through multidimensional arrays/objects,
the use of forEach,map,filter or other "new" native javascript functions is discouraged, as there is a heavy performance loss over the standard while & for loop (1).They are about 3-4 times slower. At the other side, if you know that your multidimensional array is not that big and the clients use modern browsers the map solution is the "short code" alternative (2).
DEMO
http://jsfiddle.net/axaog3n2/1/
1 https://jsperf.com/for-vs-foreach/2
2 https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/map
if you have any questions just ask.

You can use a for loop inside of another for loop.
for (var i = 0; i < array.length; i++) {
arrayOfId.push(array[i].id);
for (var j = 0; j < array[i].length; j++) {
arrayOfId.push(array[i][j]);
}
}

Use Array.map
//This will give a 2d array of ids [[2,3],[2,3]];
var ids = array.map(function(item) {
return item.items.map(function(obj) {
return obj.id
})
});
//Now flatten and merge
var idList = [];
idList = idList.concat.apply(idList , ids);
//Output:
//[12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]
Demo: http://jsfiddle.net/2kmozrr7/

simple for loop
var arrayOfId = [];
for (var i = 0; i < array.length; i++) {
arrayOfId.push(array[i].id);
if (array[i]['items'] != undefined && array[i].items.length > 0) {
for(var j = 0; j < array[i].items.length; j++) {
arrayOfId.push(array[i].items[j].id);
}
}
}

var ids = [];
for (var x = 0; x < array.length; x++) {
ids.push(array[x].id);
if (array[x].items) {
var items = array[x].items;
for (var y = 0; y < items.length; y++) {
if (items[y].id) {
ids.push(items[y].id);
}
}
}
}
Any more nested than that, you'll need to use a recursive function to do it sanely.
var results = [];
function build(array, results) {
for (var x = 0; x < array.length; x++) {
results.push(results[x].id);
if (results[x].items) {
build(results[x].items, results);
}
}
}
build(thatObject, results);

// create array for result
var b = [];
// iterate over the source array
array.forEach(function (outer) {
// get the id property and push the value to the result array
b.push(outer.id);
// iterate over the items
outer.items.forEach(function (inner) {
// get the id property of the inner array object and push the value to the result array
b.push(inner.id);
});
});

Related

Search and replace value of object property from one array with value of object property from second array?

I have two arrays of objects say 1- variants and 2- inventoryLevels. Objects in both arrays share a property which is the id. So I want to search for each variant if it's id is matched with any inventoryLevel I want to change its property named shopify_inventory_quantity with matched inventoryLevel's property available ? My words are little but confusing but take a look at code below basically it's doing properly whats needed I just want to know can it be optimized right now it's nested for loop. So any help to make it efficient would be appreciated ?
for (let i = 0; i < variants.length; i++) {
for (let j = 0; j < inventorylevels.length; j++) {
if (variants[i].id === inventorylevels[j].variant_id) {
variants[i].shopify_inventory_quantity = inventorylevels[j].available;
}
}
}
I understand you have a solution in O(n²). Assuming your ids are unique, you can reduce the time complexity to O(n) (basically what #Alireza commented):
var variants = [
{id: 0, shopify_inventory_quantity: 0},
{id: 1, shopify_inventory_quantity: 0},
{id: 2, shopify_inventory_quantity: 0}
];
var inventoryLevels = [
{id: 0, available: 10},
{id: 1, available: 2},
{id: 2, available: 3}
];
// O(n) + O(n) = O(n)
function getAvailableVariants(v, i) {
// O(n)
var inventoryLevels = i.reduce(function(inventoryLevels, inventoryLevel) {
inventoryLevels[inventoryLevel.id] = inventoryLevel;
return inventoryLevels;
}, {});
// O(n)
return v.map(variant => Object.assign(variant, {shopify_inventory_quantity: inventoryLevels[variant.id].available}));
}
var results = document.createElement('pre');
results.textContent = JSON.stringify(getAvailableVariants(variants, inventoryLevels), null, '\t');
document.body.appendChild(results);

Javascript loop an array to find numbers divisible by 3

I am needing to find the correct way to have javascript loop through an array, find all numbers that are divisible by 3, and push those numbers into a new array.
Here is what I have so far..
var array = [],
threes = [];
function loveTheThrees(array) {
for (i = 0, len = array.length; i < len; i++) {
threes = array.push(i % 3);
}
return threes;
}
So if we pass through an array of [1, 2, 3, 4, 5, 6] through the function, it would push out the numbers 3 and 6 into the "threes" array. Hopefully this makes sense.
You can use Array#filter for this task.
filter() calls a provided callback function once for each element in an array, and constructs a new array of all the values for which callback returns a true value or a value that coerces to true. callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values. Array elements which do not pass the callback test are simply skipped, and are not included in the new array.
function loveTheThrees(array) {
return array.filter(function (a) {
return !(a % 3);
});
}
document.write('<pre>' + JSON.stringify(loveTheThrees([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), 0, 4) + '</pre>');
console.log([1, 2, 3, 4, 5, 6, 7].filter(function(a){return a%3===0;}));
Array.filter() iterates over array and move current object to another array if callback returns true. In this case I have written a callback which returns true if it is divisible by three so only those items will be added to different array
var array = [],
three = [];
function loveTheThrees(array) {
for (i = 0, len = array.length; i < len; i++) {
if(array[i] % 3 == 0){
three.push(array[i]);
}
}
return three;
}
Using Filter like suggested by Nina is defiantly the better way to do this. However Im assuming you are a beginner and may not understand callbacks yet, In this case this function will work:
function loveTheThrees(collection){
var newArray = []
for (var i =0; i< collection.length;i++){
if (myArray[i] % 3 === 0){
newArray.push(collection[i])
}
}
return newArray;
}
loveTheThrees=(arr)=>arr.filter(el=>Boolean(parseFloat(el)) && isFinite(el) && !Boolean(el%3))
es6 version + skipping non numbers
loveTheThrees([null,undefined,'haha',100,3,6])
Result: [3,6]
Check if the number is divisible by 3 if so then add it to array. Try this
function loveTheThrees(array) {
for (i = 0, len = array.length; i < len; i++) {
if(array[i] % 3 == 0){
three.push(array[I]);
}
}
var originalArray = [1, 2, 3, 4, 5, 6, 7, 8, 9];
function loveTheThrees(array1) {
var threes = [];
for (var i = 0; i < array1.length; i++) {
if (array1[i] % 3 === 0) {
threes.push(array1[i]);
}
}
return threes;
}
loveTheThrees(originalArray);
In ES6:
const arr = [1, 33, 54, 30, 11, 203, 323, 100, 9];
// This single line function allow you to do it:
const isDivisibleBy3 = arr => arr.filter(val => val % 3 == 0);
console.log(isDivisibleBy3(arr));
// The console output is [ 33, 54, 30, 9 ]

Filter array of arrays by row number

I'm working on reproducing a live filter box with handsontable based on the built in search functionality at http://docs.handsontable.com/0.15.0-beta6/demo-search-for-values.html.
Right Now I'm working with the simplest use case (http://jsfiddle.net/kc11/uL3L4teL/1) from the docs.
the data is an array of arrays:
var
data = [
['Nissan', 2012, 'black', 'black'],
['Nissan', 2013, 'blue', 'blue'],
['Chrysler', 2014, 'yellow', 'black'],
['Volvo', 2015, 'yellow', 'gray']
],
As explained in the docs, In this code if you enter a search string, you get the matching cells outputted to the console using the following function:
Handsontable.Dom.addEvent(searchFiled, 'keyup', function (event) {
var queryResult = hot.search.query(this.value);
console.log(queryResult);
hot.render();
I've modified this like so:
function getRowsFromObjects(queryResult) {
rows = [];
for (var i = 0, l = queryResult.length; i < l; i++) {
debugger
rows.push(queryResult[i].row);
}
console.log('rows',rows);
return rows;
}
Handsontable.Dom.addEvent(searchFiled, 'keyup', function (event) {
var queryResult = hot.search.query(this.value);
console.log(queryResult);
rows = getRowsFromObjects(queryResult);
hot.render();
});
http://jsfiddle.net/kc11/uL3L4teL/1/
The reason for this is to grab the row numbers of the cells that match.
so Now I have 'rows' - the row numbers of the filtered rows and I can get the original data using:
data = hot.getData();
Is there an easy way to filter the data (an array of arrays ) by the row number (i.e.) the index in javascript.
My plan is to then grab the filtered data rows and re-render the table.
edit: because my question may be confusing. here's example:
data = [a,b,c,d] - the letters are arrays
rows = [0,1],
I'd like to apply a filter so the output is
data = [a,b]
You can do that with a fairly simple Array.prototype.filter call:
// Setup...
var data = [], indexes = [1, 3, 5, 7, 8, 9];
for(var i = 0; i < 15; i++) {
data.push('item #' + i);
}
// This is where the magic happens
var filtered = data.filter(function(d, ix) { return indexes.indexOf(ix) >= 0; });
// Output...
document.write('<pre>' + JSON.stringify(filtered) + '<\pre>');
Alternatively, you can reverse the logic and do that with a Array.prototype.map call for better performance but less coherent code:
// Setup...
var data = [], indexes = [1, 3, 5, 7, 8, 9];
for(var i = 0; i < 15; i++) {
data.push('item #' + i);
}
// This is where the magic happens
var filtered = indexes.map(function(i) { return data[i]; });
// Output...
document.write('<pre>' + JSON.stringify(filtered) + '<\pre>');

How to join two arrays into one two-dimensional array?

I have two arrays. How can I join them into one multidimensional array?
The first array is:
var arrayA = ['Jhon, kend, 12, 62626262662',
'Lisa, Ann, 43, 672536452',
'Sophie, Lynn, 23, 636366363'];
My other array has the values:
var arrayB = ['Jhon', 'Lisa', 'Sophie'];
How could I get an array with this format??
var jarray = [['Jhon', ['Jhon, kend, 12, 62626262662']],
['Lisa', ['Lisa, Ann, 43, 672536452']],
['Sohphie', ['Sophie, Lynn, 23, 636366363']]]
var jarray = [];
for (var i=0; i<arrayA.length && i<arrayB.length; i++)
jarray[i] = [arrayB[i], [arrayA[i]]];
However, I wouldn't call that "multidimensional array" - that usually refers to arrays that include items of the same type. Also I'm not sure why you want the second part of your arrays be an one-element array.
Here is a map version
const arrayA = ['Jhon, kend, 12, 62626262662',
'Lisa, Ann, 43, 672536452',
'Sophie, Lynn, 23, 636366363'];
const arrayB = ['Jhon', 'Lisa', 'Sophie'];
/* expected output
var jarray = [['Jhon', ['Jhon, kend, 12, 62626262662']],
['Lisa', ['Lisa, Ann, 43, 672536452']],
['Sohphie', ['Sophie, Lynn, 23, 636366363']]] */
const jarray = arrayB.map((item,i) => [item,[arrayA[i]]]);
console.log(jarray);
You can use Underscore.js http://underscorejs.org/#find
Looks through each value in the list, returning the first one that passes a truth test (iterator). The function returns as soon as it finds an acceptable element, and doesn't traverse the entire list.
var even = _.find([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
=> 2
Then, you can make the same with the array B elements and by code, make a join.
This is what I did to get what you were asking:
var jarray = [];
for (var i = 0; i < arrayB.length; i++) {
jarray[i] = [];
jarray[i].push(arrayB[i]);
var valuesList = [],
comparator = new RegExp(arrayB[i]);
for (var e = 0; e < arrayA.length; e++) {
if (comparator.test(arrayA[e])) {
valuesList.push(arrayA[e]);
}
}
jarray[i].push(valuesList);
}

sort array keys by value

I'm using javascript, and I have an array containing multiple values, which may be non-unique. I'd like to take this array and generate a new array, or ordered list, of its keys in ascending order of value. For example, if I have [ 2, 2, 4, 5, 1, 6 ], I'd like to generate [ 5, 4, 0, 1, 2, 3 ].
I was thinking of iterating over the original list and inserting each value into the new list while checking for proper placement by comparing to the existing values of the new list every time an insertion is performed. This seems wasteful, though, as I'd have to (potentially) check every value of the new list for every insertion.
Anyone have a simpler method for this?
I think you meant [ 4, 0, 1, 2, 3, 5 ].
function GetSortedKeys(values) {
var array_with_keys = [];
for (var i = 0; i < values.length; i++) {
array_with_keys.push({ key: i, value: values[i] });
}
array_with_keys.sort(function(a, b) {
if (a.value < b.value) { return -1; }
if (a.value > b.value) { return 1; }
return 0;
});
var keys = [];
for (var i = 0; i < array_with_keys.length; i++) {
keys.push(array_with_keys[i].key);
}
return keys;
}
var array = [2, 2, 4, 5, 1, 6];
alert(GetSortedKeys(array));
This is the simplest method I can come up with on Javascript, unfortunately.
Using the nice Underscore.JS:
var get_sorted_keys = function(values) {
var keys_idx = [], i;
for (i = 0; i < values.length; i++) {
keys_idx.push(i);
}
var keys = _.sortBy(keys_idx, function(idx){ return values[idx]; });
return keys;
};
var array = [2, 2, 4, 5, 1, 6];
console.log("Sorted keys:", get_sorted_keys(array));
Output:
Sorted keys: [4, 0, 1, 2, 3, 5]

Categories

Resources