Find Value in JSON array and delete found node from parent node - javascript

var trees = [
{
name: "alex",
lastname: "watson",
city: "California",
state: "Alameda",
childrens: [
{ name: "shane watson", city: "Troy", state: "Alabama" },
{
name: "adam watson",
city: "Palmer",
state: "Alaska",
childrens: [
{ name: "ana watson", city: "Avondale", state: "Arizona" },
{ name: "ama watson", city: "Douglas", state: "Arizona" }
]
}
]
},
{
name: "adam",
lastname: "ronaldo",
city: "Bradenton",
state: "Florida",
childrens: [
{ name: "austin ronaldo", city: "Alhambra", state: "California" },
{
name: "kira ronaldo",
city: "Calexico",
state: "California",
childrens: [
{ name: "sam ronaldo", city: "Chico", state: "California" },
{
name: "godwin ronaldo",
city: "Eureka",
state: "California",
childrens: [
{ name: "michael ronaldo", city: "Buffalo", state: "New York" }
]
}
]
}
]
}
];
Find out city in JSON array variable trees (eg. city = "Buffalo" or name = "Godwin ronaldo")
delete found nodes from parent tree variable.
this function gives matching nodes:
function findMatchingNodes(nodes, predicate) {
const results = [];
function walk(node) {
if (predicate(node)) {
results.push(node);
}
(node.childrens || []).forEach(walk);
}
nodes.forEach(walk);
return results;
}
Function calling
const matches = findMatchingNode(
trees,
(n) => n.city === 'Buffalo' || n.name === 'godwin ronaldo'
);
I want to delete the matching node.
matches.forEach(node => {
delete node;
});
output: SyntaxError: Deleting local variable in strict mode
https://jsfiddle.net/5sve3nxc/
Working fiddle to push trees child node. I want to delete node instead of pushing.

While you need to splice the array, if the predicate is true, you need to iterate from the end of the array, to maintain the index.
function deleteFromArray(array, predicate) {
var i = array.length;
while (i--) {
if (predicate(array[i])) {
array.splice(i, 1);
continue;
}
if (array[i].children) {
deleteFromArray(array[i].children, predicate);
}
}
}
var tree = [{ name: "alex", lastname: "watson", city: "California", state: "Alameda", children: [{ name: "shane watson", city: "Troy", state: "Alabama" }, { name: "adam watson", city: "Palmer", state: "Alaska", children: [{ name: "ana watson", city: "Avondale", state: "Arizona" }, { name: "ama watson", city: "Douglas", state: "Arizona" }] }] }, { name: "adam", lastname: "ronaldo", city: "Bradenton", state: "Florida", children: [{ name: "austin ronaldo", city: "Alhambra", state: "California" }, { name: "kira ronaldo", city: "Calexico", state: "California", children: [{ name: "sam ronaldo", city: "Chico", state: "California" }, { name: "godwin ronaldo", city: "Eureka", state: "California", children: [{ name: "michael ronaldo", city: "Buffalo", state: "New York" }] }] }] }];
deleteFromArray(tree, ({ city, name }) => city === 'Buffalo' || name === 'godwin ronaldo');
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

Optimal way to find union of two data sets

I am working on a side project where I am comparing two different databases and want to find the common elements of the data sets based on the "id" field. I want to know if there is an optimal solution instead of using two nested for loops. Is there a way to do it with a hash map? Many Thanks!
Below is the sample code I am working with.
UPDATE all ids are unique with no possibility of there being a duplicate
// data set 1
const set1 = [
{
id: "001",
name: "bob",
age: "50",
location: "texas"
},
{
id: "002",
name: "bill",
age: "51",
location: "texas"
},
{
id: "003",
name: "ben",
age: "52",
location: "texas"
},
{
id: "004",
name: "cam",
age: "53",
location: "texas"
},
{
id: "005",
name: "max",
age: "54",
location: "texas"
}
]
// data set 2
const set2 = [
{
id: "001",
name: "bob"
},
{
id: "002",
name: "bill"
}
]
// I want to create a function where I find the the common elements of the two lists based on id and put the common element of data set 1 into a list and return that list
const findUnion(set1, set2) {
// logic here, I know I can do a nested for loop but is there a more efficient way such as
// using a hashmap? ( Map() object? )
}
// desired output
const output = [
{
id: "001",
name: "bob",
age: "50",
location: "texas"
},
{
id: "002",
name: "bill",
age: "51",
location: "texas"
}
]
You can use Sets for efficient lookup:
const ids1 = new Set(set1.map(({id}) => id));
const ids2 = new Set(set2.map(({id}) => id));
const output = set1.filter(({id}) => ids1.has(id) && ids2.has(id));
console.log(output);
First of all, you're looking for the intersection, not the union.
As others have said, we can use a Set to track uniqueness. This gives us near O(1) lookup time, and allows us algorithm that runs in something like O(m + n) time where m and n are the sizes of your sets:
const intersection = (s1, s2, ids = new Set (s2 .map (x => x .id))) =>
s1 .filter (({id}) => ids .has (id))
const set1 = [{id: "001", name: "bob", age: "50", location: "texas"}, {id: "002", name: "bill", age: "51", location: "texas"}, {id: "003", name: "ben", age: "52", location: "texas"}, {id: "004", name: "cam", age: "53", location: "texas"}, {id: "005", name: "max", age: "54", location: "texas"}]
const set2 = [{id: "001", name: "bob"}, {id: "002", name: "bill"}]
console .log (intersection (set1, set2))
.as-console-wrapper {max-height: 100% !important; top: 0}
First we combine into one long array. Then group by id using reduce method. Each group contains the item and count of appearances. Finally, for each of the groups, return only those with count of appearances > 1.
Edit: fixed algorithm see code.
Edit 2: Made it more generic so order of items won't matter. This is by extending the duplicates rather then replacing them.
function findUnion(set1, set2) {
// first remove duplicates from each set
// bonus: collect duplicates
var duplicates;
function dedup(set) {
duplicates = []
return Object.values(set.reduce(function(agg, item) {
var merged = item;
if (agg[item.id]) {
merged = { ...agg[item.id],
...item
}
duplicates.push(merged)
}
agg[item.id] = merged;
return agg
}, {}));
}
set1 = dedup(set1);
set2 = dedup(set2);
// then combine
var combined = [...set1, ...set2]
// then remove duplicates again, this time keep them
dedup(combined)
return duplicates;
}
// data set 1
const set1 = [{
id: "001",
name: "bob",
age: "50",
location: "texas"
},
{
id: "002",
name: "bill",
age: "51",
location: "texas"
},
{
id: "003",
name: "ben",
age: "52",
location: "texas"
},
{
id: "004",
name: "cam",
age: "53",
location: "texas"
},
{
id: "005",
name: "max",
age: "54",
location: "texas"
},
{
id: "005",
name: "max",
age: "54",
location: "texas"
},
{
id: "005",
name: "max",
age: "54",
location: "texas"
}
]
// data set 2
const set2 = [{
id: "001",
name: "bob"
},
{
id: "002",
name: "bill"
}
]
// desired output
const output = [{
id: "001",
name: "bob",
age: "50",
location: "texas"
},
{
id: "002",
name: "bill",
age: "51",
location: "texas"
}
]
console.log(findUnion(set1, set2))

Nested filter returning empty array

Below is the data that I am receiving and I am trying to filter so that a new array contains only objects with the desired location.
However, I'm running into an issue where my function is returning [], an empty array.
data:
[
{ data: [[Object], [Object], [Object]], id: 1 },
{ data: [[Object]], id: 2 },
{ data: [[Object], [Object], [Object], [Object]], id: 3 }
];
data[1]:
{"data": [{"name": "Joe", "job": "N/A", "location": "Los Angeles"}], "id": 2}
This is my current function:
const locations = ["Los Angeles", "Chicago"];
...
const filteredData = data.filter((i) =>
i.data.filter((j) => locations.includes(j.location)),
);
return filteredData;
What is wrong and how can I fix this and get it filtering correctly?
In the callback you pass to the Array.filter(), you need to return a boolean value to filter the array. If you do not return anything, the filter returns an empty array.
But in your case, you are returning inner filtered array that returns at least an empty array and the outer filter behaves it as a true value. So the outer filter will return all of the items in the original array. (not an empty one as you stated)
Also you are returning filteredData in a place where it results in a syntax error.
const data = [
{"data": [{"name": "Joe", "job": "N/A", "location": "Los Angeles"}], "id": 2},
{"data": [{"name": "Jane", "job": "N/A", "location": "Charlotte"}], "id": 3},
]
const locations = ["Los Angeles", "Chicago"];
const filteredData = data.filter((i) =>
i.data.filter((j) => locations.includes(j.location)).length > 0,
);
console.log(filteredData);
Another Option is use some() to get your expected result. This way you don't need to loop through all item in data array comparing to filter()
const data = [
{ data: [{ name: "Joe", job: "N/A", location: "Los Angeles" }], id: 2 },
{ data: [{ name: "Jane", job: "N/A", location: "Charlotte" }], id: 3 },
{ data: [{ name: "Sam", job: "N/A", location: "SSS" }], id: 4 },
{
data: [
{ name: "John", job: "N/A", location: "AAA" },
{ name: "Doe", job: "N/A", location: "BBB" },
],
id: 5,
},
];
const locations = ["Los Angeles", "Chicago", "AAA"];
const existData = data.filter(el =>
el.data.some(item => locations.includes(item.location))
);
console.log(existData);
If you also want to filter the data array, you can do like below.
const data = [
{ data: [{ name: "Joe", job: "N/A", location: "Los Angeles" }], id: 2 },
{ data: [{ name: "Jane", job: "N/A", location: "Charlotte" }], id: 3 },
{ data: [{ name: "Sam", job: "N/A", location: "SSS" }], id: 4 },
{
data: [
{ name: "John", job: "N/A", location: "AAA" },
{ name: "Doe", job: "N/A", location: "BBB" },
],
id: 5,
},
];
const locations = ["Los Angeles", "Chicago", "AAA"];
const filteredData = data.reduce((acc, cur) => {
const filteredItem = cur.data.filter(item => locations.includes(item.location));
if (filteredItem.length) {
acc.push({ ...cur, data: filteredItem });
}
return acc;
}, []);
console.log(filteredData);

Move two items of array to front in javascript

I have an array address like so
[
{
id: "83",
country: "China",
type: "NORMAL"
},
{
id: "84",
country: "California",
type: "HOME"
},
{
id: "85",
country: "Brazil",
type: "NORMAL"
},
{
id: "86",
country: "India",
type: "WORK"
},
]
How I move two items with type is HOME and WORK to the front of array like so: HOME first then come WORK then another.
[
{
id: "84",
country: "California",
type: "HOME"
},
{
id: "86",
country: "India",
type: "WORK"
},
{
id: "83",
country: "China",
type: "NORMAL"
},
{
id: "85",
country: "Brazil",
type: "NORMAL"
},
]
Thank you :))
I think you can use JS array sort method, I provide you an example below (pseudo code):
const order = ['HOME', 'WORK', 'NORMAL'];
const arr = [{id: "83", country: "China", type: "NORMAL"}, {...}] // your array to sort
const sorted = arr.sort((a, b) => order.indexOf(a.type) > order.indexOf(b.type));

Filter a list based on a selection

Given the data below, I have two select lists, the first select list is to display the name of each person... the second select list is two display the name of the children of the selected person. Using lodash what is the easiest way to do this?
const people = [{
id: "1",
name: "bob",
gender: "male",
children: [{
id: "1",
name: "sarah"
}]
},
{
id: "2",
name: "tom",
gender: "male",
children: [{
id: "1",
name: "lisa"
}]
},
{
id: "3",
name: "sue",
gender: "female",
children: [{
id: "1",
name: "larry"
}]
}
]
Please find the solution as below:
import map from "lodash/map";
import partialRight from "lodash/partialRight";
import pick from "lodash/pick";
import find from "lodash/find";
const test = [
{
id: "2",
name: "tom",
gender: "male",
children: [
{
id: "1",
name: "lisa"
}
]
},
{
id: "3",
name: "sue",
gender: "female",
children: [
{
id: "1",
name: "larry"
}
]
}
];
// Person selection list
const persons = map(test, partialRight(pick, ["id", "name", "gender"]));
// Replace selected person value in `persons[0]`.
const childrens = find(test, item => item.id === persons[0].id).children;

Adding Dynamic elements/rows to multi dimensional Json array in Angularjs

I have a JSon object array that looks as below:
var myObject= [
{"name":'Tom', "city":'Chicago',"GroupCode":'1'},
{"name":'Harry', "city":'Wisconsin',"GroupCode":'1'},
{"name":'Rob', "city":'Los Angeles',"GroupCode":'2'},
{"name":'Peter', "city":'Seattle',"GroupCode":'2'},
{"name":'Dave', "city":'New York',"GroupCode":'3'},
{"name":'Steve', "city":'Boston',"GroupCode":'3}
];
I wanted to a add a new row with some sample values when ever the GroupCode is changing. My result shall look like :
var myObject= [
{"name":'Tom', "city":'Chicago',"GroupCode":'1'},
{"name":'Harry', "city":'Wisconsin',"GroupCode":'1'},
{"name":'--', "city":'--',"GroupCode":'--'},
{"name":'Rob', "city":'Los Angeles',"GroupCode":'2'},
{"name":'Peter', "city":'Seattle',"GroupCode":'2'},
{"name":'--', "city":'--',"GroupCode":'--'},
{"name":'Dave', "city":'New York',"GroupCode":'3'},
{"name":'Steve', "city":'Boston',"GroupCode":'3}
];
How can i do that ? Please help !
You can do it like this:
var myObject = [{
"name": 'Tom',
"city": 'Chicago',
"GroupCode": '1'
}, {
"name": 'Harry',
"city": 'Wisconsin',
"GroupCode": '1'
}, {
"name": 'Rob',
"city": 'Los Angeles',
"GroupCode": '2'
}, {
"name": 'Peter',
"city": 'Seattle',
"GroupCode": '2'
}, {
"name": 'Dave',
"city": 'New York',
"GroupCode": '3'
}, {
"name": 'Steve',
"city": 'Boston',
"GroupCode": '3'
}];
//store the first groupcode
var gc = myObject[0].GroupCode;
myObject.forEach(function(ob, index) {
if (gc != ob.GroupCode) {
gc = ob.GroupCode;
//insert this object
myObject.splice(index, 0, {
"name": '--',
"city": '--',
"GroupCode": '--'
});
}
})
console.log(myObject)
working code here

Categories