Get index of parent object in nested object array - javascript

I have this array:
[
{
elements: [
{ id: '123', field: 'value' }
{ id: '456', field: 'value' }
]
}
{
elements: [
{ id: '789', field: 'value' }
]
}
]
Now I need to get the index of the first level object searching by an id:
searching for id = '456' should give me 0, id = '789' should give me 1

You can do this with findIndex() and some()
var arr = [{
elements: [{
id: '123',
field: 'value'
}, {
id: '456',
field: 'value'
}]
}, {
elements: [{
id: '789',
field: 'value'
}]
}]
var i = arr.findIndex(function(o) {
return o.elements.some(function(e) {
return e.id == 456;
})
})
console.log(i)

Get the feeling that something could be fixed to rethink this. But who knows.
456 should give u id 1 and so should 789 aswell.
var mapped = whatEverObject[0].elements.map(function(obj){ //0 = first
return obj.id;
})
console.log(mapped.indexOf(456)) // will give you 1 since id:123 is id 0 in the first elements array.

You can make a lookup table. It will be much faster if you do several lookups.
Live Example
var table = makeNestedLookupTable(example);
// table[789] would be 1 if the array in the question were "example"
function makeNestedLookupTable(data) {
return data.reduce(function(lookup, obj, topIndex) {
return obj.elements.reduce(function(lookup, element) {
lookup[element.id] = topIndex;
return lookup;
}, lookup);
}, {});
}

You can use this function getIndex which loops through the array and matches the id of the element with the given id and returns the index.This solution will work in all browsers.
var arr = [
{
elements: [
{ id: '123', field: 'value' }
{ id: '456', field: 'value' }
]
}
{
elements: [
{ id: '789', field: 'value' }
]
}
];
function getIndex(arr, id) {
var i, ii, len, elemlen;
for (i = 0, len = arr.length; i < len; i++) {
elements = arr[i].elements;
for (ii = 0, elemlen = elements.length; ii < elemlen; ii++) {
if (elements[ii].id === id) {
return i;
}
}
}
}
var index = getIndex(arr, '456');

Here is a generic code where you can send an array and the lookup attribute:
function giveLevel(a,attr){
for(var i=0;i<a.length;i++){
var o = a[i];
var tmp = JSON.stringify(o);
if(tmp.indexOf(attr)!==-1){
return i;
}
}
}
var a = [{elements: [
{ id: '123', field: 'value' },
{ id: '456', field: 'value' }
]
},
{
elements: [
{ id: '789', field: 'value' }
]
}
];
giveLevel(a,'"id":"789"'); // returns 1

Related

How to update a value in nested array based on the given index and return original array in javascript?

I have an index '3_1_0' and the following array:-
var fields = [
{
name: 'a'
},
{
name: 'b'
},
{
name: 'c'
},
{
name: 'd',
fields: [
{
name: 'd1'
},
{
name: 'd2',
fields: [
{
name: 'd2.1'
}
]
}
]
}
]
I need to extract the element from the above fields array based on the index. so 3_1_0 will extract following
{
name: 'd2.1'
}
Update the value from d2.1 to some other value like 'new_d2.1' and attach the updated value at the same index in original fields array and return the updated fields array. How this can be done?
You can use Array.reduce to get the desired result. We start by splitting the index into an array, then reducing to get the result.
We'll use some Optional Chaining to ensure we'll return undefined if no value is found (say our index was '7_10_20').
Once we've found our object, we can set the required property.
const fields = [ { name: 'a' }, { name: 'b' }, { name: 'c' }, { name: 'd', fields: [ { name: 'd1' }, { name: 'd2', fields: [ { name: 'd2.1' } ] } ] } ];
const index = '3_1_0'
function setValue(fields, index, property, value) {
const obj = index.split('_').reduce((acc, key) => {
return acc?.[key] || acc?.fields?.[key];
}, fields);
// Only update if we actually find anything
if (obj) {
obj[property] = value
}
}
setValue(fields, '3_1_0', 'name', 'new_d2.1');
console.log("Fields:", fields);
const data = [{ name: 'a' }, { name: 'b' }, { name: 'c' }, { name: 'd', fields: [ { name: 'd1' }, { name: 'd2', fields: [ { name: 'd2.1' } ] } ] } ];
let givenIdxs = "3_1_0";
let indexes = givenIdxs.split("_");
let result = data[indexes[0]];
for(let idx = 1; idx < indexes.length; idx++){
result = result.fields[indexes[idx]];
}
console.log(result);

How to get index of a 2d array of 2 similar structure ones with same value

Sorry the title may not present well.
I got two 2d arrays with similar structure.
array A:
arrayA[0]['account_name'] = 'a0';
arrayA[1]['account_name'] = 'a1';
arrayA[2]['account_name'] = 'a2';
And array B:
arrayB[0]['account_name'] = 'a1';
arrayB[1]['account_name'] = 'b0';
arrayB[2]['account_name'] = 'c0';
arrayB[3]['account_name'] = 'a0';
arrayB[4]['account_name'] = 'd3';
arrayB[5]['account_name'] = 'e8';
arrayB[6]['account_name'] = 'a3';
arrayB[7]['account_name'] = 'b4';
arrayB[8]['account_name'] = 'b1';
Now I know arrayA[0]['account_name'] equals to "a0", how can I search efficiently to check if it also exists in array B / know its position in array B? And I would like to loop for all values in array A.
const a = [
{ name: 'a0' },
{ name: 'a1' },
{ name: 'b2' }
];
const b = [
{ name: 'a0' },
{ name: 'a1' },
{ name: 'a2' },
{ name: 'b0' },
{ name: 'b1' },
{ name: 'b2' }
];
a.forEach((aa, i) => {
let found;
b.forEach((bb, j) => {
if(aa.name === bb.name) {
found = {
index: j,
value: aa.name
};
return true;
}
});
console.log(found);
});

Constructing alphabetized array of objects

I have an array of objects with a name property...
var myList = [{
name: 'Apple'
}, {
name: 'Nervousness',
}, {
name: 'Dry'
}, {
name: 'Assign'
}, {
name: 'Date'
}]
Essentially, I am trying to create an array set up like this:
[{
name: 'A',
items: [{
name: 'Apple'
}, {
name: 'Assign'
}]
}, {
name: 'D',
items: [{
name: 'Date',
}, {
name: 'Dry',
}]
}, {
name: 'N',
items: [{
name: 'Nervousness',
}]
}];
Basically, my array of objects needs to be alphabetized, placed into a new object with a parent key/value of 'name' with the corresponding letter.
I can alphabetize them as follows...
myList.sort(function (a, b) {
if (a.name < b.name) return -1;
if (a.name > b.name) return 1;
return 0;
});
Then I can create an array of the first letters...
var headerLetters = [];
angular.forEach(myList, function (item) {
var firstLetter = item.name.charAt(0);
if (headerLetters.indexOf(firstLetter) === -1) {
headerLetters.push(firstLetter);
}
});
But then this is where I am stuck... I can check for duplicate first letters, but then how would I iterate through my list of objects and push them into a new object array in alphabetical order?
Assuming you sort them alphabetically first then you can always just check the latest item in the array and see if it matches the current name.
var headerLetters = [];
angular.forEach(myList, function(item) {
var firstLetter = item.name[0];
var lastObj = headerLetters[headerLetters.length - 1];
if (!lastObj || lastObj.name !== firstLetter) {
lastObj = {
name: firstLetter,
items: []
};
headerLetters.push(lastObj);
}
lastObj.items.push(item);
});

Search deep in array and delete

I got the following array:
var arr = [
{
1: {
id: 1,
title: 'test'
},
children: [
{
1: {
id: 2,
title: 'test2'
}
}
]
}
];
The objects directly in the array are the groups. The 1: is the first language, 2: is second etc. The id is stored in every language object (due to the database I'm using). The children array is built the same way as the 'arr' array.
Example of multiple children:
var arr = [
{
1: {
id: 1,
title: 'test'
},
children: [
{
1: {
id: 2,
title: 'test2'
},
children: [
{
1: {
id: 3,
title: 'test3',
},
children: []
}
]
}
]
}
];
Now I need to delete items from this array. You can have unlimited children (I mean, children can have children who can have children etc.). I have a function which needs an ID parameter sent. My idea is to get the right object where the ID of language 1 is the id parameter. I got this:
function deleteFromArray(id)
{
var recursiveFunction = function (array)
{
for (var i = 0; i < array.length; i++)
{
var item = array[i];
if (item && Number(item[1].ID) === id)
{
delete item;
}
else if (item && Number(item[1].ID) !== id)
{
recursiveFunction(item.children);
}
}
};
recursiveFunction(arr);
}
However, I'm deleting the local variable item except for the item in the array. I don't know how I would fix this problem. I've been looking all over the internet but haven't found anything.
This proposal features a function for recursive call and Array.prototype.some() for the iteration and short circuit if the id is found. Then the array is with Array.prototype.splice() spliced.
var arr = [{ 1: { id: 1, title: 'test' }, children: [{ 1: { id: 2, title: 'test2' }, children: [{ 1: { id: 3, title: 'test3', }, children: [] }] }] }];
function splice(array, id) {
return array.some(function (a, i) {
if (a['1'].id === id) {
array.splice(i, 1)
return true;
}
if (Array.isArray(a.children)) {
return splice(a.children, id);
}
});
}
splice(arr, 2);
document.write('<pre>' + JSON.stringify(arr, 0, 4) + '</pre>');
var arr = [{ 1: { id: 1, title: 'test' }, children: [{ 1: { id: 2, title: 'test2' }, children: [{ 1: { id: 3, title: 'test3', }, children: [] }] }] }];
function deleteFromArray(id) {
function recursiveFunction(arr) {
for (var i = 0; i < arr.length; i++) {
var item = arr[i];
if (item && Number(item[1].id) === id) {
arr.splice(i, 1);
} else if (item && Number(item[1].id) !== id) {
item.children && recursiveFunction(item.children);
}
}
};
recursiveFunction(arr);
};
deleteFromArray(2);
document.getElementById("output").innerHTML = JSON.stringify(arr, 0, 4);
<pre id="output"></pre>
jsfiddle: https://jsfiddle.net/x7mv5h4j/2/
deleteFromArray(2) will make children empty and deleteFromArray(1) will make arr empty itself.

How do I remove duplicate objects in an array by field in Javascript?

I have an array of objects:
[{
id: 1,
name: 'kitten'
}, {
id: 2,
name: 'kitten'
},{
id: 3,
name: 'cat
}]
How do I remove the second kitten? Sorting into an array of names doesn't work, because I can't know if I am deleting id 1 or or id 2. So, I'm not quite sure how to do this.
You can use an additional hash-map to store names found so far. When you process a next object if it's name is already in the hash-map it is a duplicate and you can remove it.
var duplicates = {};
for (var i = 0; i < array.length) {
var obj = array[i];
if (! duplicates[obj.name]) {
duplicates[obj.name] = 1;
i++;
} else {
array.splice(i, 1);
}
}
there is the lodash library.
You could use the uniq
var array = [{
id: 1,
name: 'kitten'
}, {
id: 2,
name: 'kitten'
},{
id: 3,
name: 'cat'
}];
var asd = _.uniq(array,'name');
console.log(asd);
Gives an output:
[ { id: 1, name: 'kitten' }, { id: 3, name: 'cat' } ]
as it written in the documentation "only the first occurence of each element is kept".
var arr =[{
id: 1,
name: 'kitten'
}, {
id: 2,
name: 'kitten'
},{
id: 3,
name: 'cat'
}];
var results = [];
var idsSeen = {}, idSeenValue = {};
for (var i = 0, len = arr.length, name; i < len; ++i) {
name = arr[i].name;
if (idsSeen[name] !== idSeenValue) {
results.push(arr[i]);
idsSeen[name] = idSeenValue;
}
}
console.log(results);

Categories

Resources