Filter on two arrays same time? - javascript

I have two arrays:
const array1 = [{
"id": "4521",
"name": "Tiruchirapalli",
"stateId": "101"
},
{
"id": "1850",
"name": "Tenkasi",
"stateId": "101"
},
{
"id": "202",
"name": "Thanjavur",
"stateId": "101"
},
{
"id": "505",
"name": "Ernakulam",
"stateId": "102"
},
];
And now array2
const array2 = [{
"id": 1850,
"cityName": "Tenkasi",
"aliasNames": [
"Thenkasi"
]
},
{
"id": 4521,
"cityName": "Tiruchirapalli",
"aliasNames": [
"Trichy"
]
},
{
"id": 202,
"cityName": "Thanjavur",
"aliasNames": [
"Tanjore"
]
},
{
"id": 505,
"cityName": "Ernakulam",
"aliasNames": [
"Kochi",
"Cochin"
]
},
];
what i need to do is, how to filter both the arrays at same time ( or filter first one and then second which ever one is performance effective ).
For instance, when user types "Kochi", first it should check on array1 to find if its has name="Kochi", if it has then we can set the state with that and if it doesnt have we need to find it on array2 and the update the state !
Which is fast and effective way to handle this - ( array1 has 2500 records and array2 has 990 records ) so performance / speed is also a concern
My attempt:
searchFilterFunction = text => {
this.setState({ typedText: text });
const newData = array1.filter(item => {
const itemData = `${item.name.toUpperCase()}`;
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
this.setState({ data: newData});
};
How to implement the second filter in optimized way ?

For instance, when user types "Kochi", first it should check on array1
to find if its has name="Kochi", if it has then we can set the state
with that and if it doesnt have we need to find it on array2 and the
update the state !
I would do something like this with Array.find.
if( array1.find(item=>item.name.toUpperCase() === text) ) {
// set state
} else if( array2.find(item=>item.cityName.toUpperCase() === text) ) {
// set state
}
A refined form would be
let result = array1.find(item=>item.name.toUpperCase() === text);
// check in array 2 as we cannot find in array 1
if(!result) {
result = array2.find(item=>{
// check in aliasNames and in cityName
return item.cityName.toUpperCase() === text || item.aliasNames.includes(text);
}
);
}
if(result) {
setState(result);
} else {
// place not found
}
Regarding the performance based on your array count you will not see much difference. If you want to save some milliseconds you can check the array with least count first as mentioned in one of the comments. But the time also varies based on were the element is in array.

I think this is the most optimal solution because nesting the two filter won't work as you need to filter from first array and then second.
const array1 = [{
"id": "4521",
"name": "Tiruchirapalli",
"stateId": "101"
},
{
"id": "1850",
"name": "Tenkasi",
"stateId": "101"
},
{
"id": "202",
"name": "Thanjavur",
"stateId": "101"
},
{
"id": "505",
"name": "Ernakulam",
"stateId": "102"
},
];
const array2 = [{ "id": 1850, "cityName": "Tenkasi",
"aliasNames": [
"Thenkasi"
]
},{"id": 4521,"cityName": "Tiruchirapalli",
"aliasNames": [
"Trichy"
]
},
{
"id": 202,
"cityName": "Thanjavur",
"aliasNames": [
"Tanjore"
]
},
{
"id": 505,
"cityName": "Ernakulam",
"aliasNames": [
"Kochi",
"Cochin"
]
},
];
function filter(text) {
// Complexity Linear
const filter_array = array1.filter((a) => {
return (a.name === text)
});
if (filter_array.length > 0) {
//Set State and return
}
//Complexity Linear and includes complexity Linear O(sq(m*n)) where n is //the aliasName record
const filter_array2 = array2.filter((a) => {
return a.cityName === text || a.aliasNames.includes(text);
});
return filter_array2 //Set State filter array 2
}
console.log(filter("Kochi"));

Related

Loop through an array of objects and update parent object count if child object exists

I am using Angular 13 and I have an array of objects like this:
[{
"name": "Operating System",
"checkedCount": 0,
"children": [{
"name": "Linux",
"value": "Redhat",
"checked": true
},
{
"name": "Windows",
"value": "Windows 10"
}
]
},
{
"name": "Software",
"checkedCount": 0,
"children": [{
"name": "Photoshop",
"value": "PS",
"checked": true
},
{
"name": "Dreamweaver",
"value": "DW"
},
{
"name": "Fireworks",
"value": "FW",
"checked": true
}
]
}
]
I would like to loop through the array, check if each object has a children array and it in turn has a checked property which is set to true, then I should update the checkedCount in the parent object. So, result should be like this:
[{
"name": "Operating System",
"checkedCount": 1,
"children": [{
"name": "Linux",
"value": "Redhat",
"checked": true
},
{
"name": "Windows",
"value": "Windows 10"
}
]
},
{
"name": "Software",
"checkedCount": 2,
"children": [{
"name": "Photoshop",
"value": "PS",
"checked": true
},
{
"name": "Dreamweaver",
"value": "DW"
},
{
"name": "Fireworks",
"value": "FW",
"checked": true
}
]
}
]
I tried to do it this way in angular, but this is in-efficient and results in an error saying this.allFilters[i].children[j] may be undefined. So, looking for an efficient manner to do this.
for(let j=0;i<this.allFilters[i].children.length; j++) {
if (Object.keys(this.allFilters[i].children[j]).length > 0) {
if (Object.prototype.hasOwnProperty.call(this.allFilters[i].children[j], 'checked')) {
if(this.allFilters[i].children[j].checked) {
this.allFilters[i].checkedCount++;
}
}
}
}
Use a nested for loop to check all the children. If checked is truthy, increment the count of the parent. You don't need to check if parent.children has any elements since if there are no elements the loop won't run anyways.
// minified data
const data = [{"name":"Operating System","checkedCount":0,"children":[{"name":"Linux","value":"Redhat","checked":!0},{"name":"Windows","value":"Windows 10"}]},{"name":"Software","checkedCount":0,"children":[{"name":"Photoshop","value":"PS","checked":!0},{"name":"Dreamweaver","value":"DW"},{"name":"Fireworks","value":"FW","checked":!0}]}];
for (const parent of data) {
for (const child of parent.children) {
if (child.checked) parent.checkedCount++;
}
}
console.log(data);
No need to complicate it like that, you just need to check checked property in children.
data.forEach((v) => {
v.children.forEach((child) => {
if (child.checked) {
v.checkedCount++;
}
});
});
Using filter + length on children array should do the job:
const data = [{"name":"Operating System","checkedCount":null,"children":[{"name":"Linux","value":"Redhat","checked":true},{"name":"Windows","value":"Windows 10"}]},{"name":"Software","checkedCount":null,"children":[{"name":"Photoshop","value":"PS","checked":true},{"name":"Dreamweaver","value":"DW"},{"name":"Fireworks","value":"FW","checked":true}]}];
data.forEach(itm => {
itm.checkedCount = itm.children?.filter(e => e.checked === true).length ?? 0;
});
console.log(input);
I would suggest going functional.
Using map
const children = arr.map(obj => obj.children);
const result = children.map((child, idx) => {
const checkedCount = child.filter(obj => obj.checked)?.length;
return {
...arr[idx],
checkedCount
};
});
console.log(result)
or using forEach
const result = [];
const children = arr.map(obj => obj.children);
children.forEach((child, idx) => {
const checkedCount = child.filter(obj => obj.checked)?.length;
result[idx] = {
...arr[idx],
checkedCount
};
});
console.log(result)

How to filter an objects where is employeeId equals to some value

I'm using knockoutjs, but the question is really in Javascript domain.
I have variable vm.filteredSerivces() which contains all services by all employees.
Now, I want to just preserve those filteredSerivces where is vm.filteredSerivces()[0].GroupedServices[x].EmployeeId == 3684 (x is the number of index number of each object in GroupedServices object list)
I tried as follows:
var filteredSrvcs = vm.filteredSerivces()[0].GroupedServices.filter(x => x.EmployeeId != Id).remove();
vm.filteredSerivces(filteredSrvcs );
But I changed structure in that way, and my bindings in html is not corresponding.
Is there any other way to just remove this sub-sub object, and to preserve a structure as it is?
Here is the
Here's an example that maps a new array of new objects and the filter is set to only include the GroupedServices items where Id == 2000
let res = data.map(({ServiceTypeName, GroupedServices}) =>{
GroupedServices= GroupedServices.filter(({Id}) => Id == 2000);
return {ServiceTypeName,GroupedServices }
})
console.log(res)
<script>
let data =
[
{
"ServiceTypeName": "Type 1",
"GroupedServices": [{
"Id": 1,
"Name": "A"
}, {
"Id": 2,
"Name": "A"
},
{
"Id": 28456,
"Name": "AGSADGJS"
}]
},
{
"ServiceTypeName": "Type 2",
"GroupedServices": [{
"Id": 1203,
"Name": "AHASJ"
}, {
"Id": 2000,
"Name": "AHSJD"
},
{
"Id": 284536,
"Name": "UEHNCK"
}]
}];
</script>

How to get the duplicates objects in an array?

I have an array like this:
var clients=[{"id":1,"name":"john","age":20},
{"id":3,"name":"dean","age":23},
{"id":12,"name":"harry","age":14},
{"id":1,"name":"sam","age":22},
{"id":13,"name":"Bolivia","age":16},
{"id":7,"name":"sabi","age":60},
{"id":7,"name":"sahra","age":40},
{"id":4,"name":"natie","age":53},{"id":7,"name":"many","age":22}]
I want to find the duplicate objects and cluster them like this:
[
{
"id":1,
"clients":[
{"id":1,"name":"john","age":20},
{"id":1,"name":"sam","age":22}
]
},
{
"id":7,
"clients":[
{"id":7,"name":"sabi","age":60},
{"id":7,"name":"sahra","age":40},
{"id":7,"name":"many","age":22}
]
}
]
can I do that with filter() like this:clients.reduce(//code hier)?
reduce() is tailor made for this. When you want to aggregate over an array and get a computed result, you should use reduce().
find() is another array method, which helps in finding an array element based on a condition (here the matching of id property).
var clients=[{"id":1,"name":"john","age":20},
{"id":3,"name":"dean","age":23},
{"id":12,"name":"harry","age":14},
{"id":1,"name":"sam","age":22},
{"id":13,"name":"Bolivia","age":16},
{"id":7,"name":"sabi","age":60},
{"id":7,"name":"sahra","age":40},
{"id":4,"name":"natie","age":53},{"id":7,"name":"many","age":22}]
let ans = clients.reduce((agg,x,index) => {
let findI = agg.find( a =>
a.id === x.id
);
if(findI) findI.clients.push(x);
else {
agg.push({
id : x.id,
clients : [x]
});
}
return agg;
},[]);
console.log(ans);
The simplest solution would be to loop over the clients and check for an existing object with the same id. If yes, push to clients array. Or else, just create one.
var clients = [{ "id": 1, "name": "john", "age": 20 },
{ "id": 3, "name": "dean", "age": 23 },
{ "id": 12, "name": "harry", "age": 14 },
{ "id": 1, "name": "sam", "age": 22 },
{ "id": 13, "name": "olivia", "age": 16 },
{ "id": 7, "name": "sabi", "age": 60 },
{ "id": 7, "name": "sahra", "age": 40 },
{ "id": 4, "name": "natie", "age": 53 }, { "id": 7, "name": "kany", "age": 22 }]
const groups = [];
for (let client of clients) {
const existingGroup = groups.find(group => group.id == client.id)
if (existingGroup)
existingGroup.clients.push(client);
else {
groups.push({ id: client.id, clients: [client] });
}
}
console.log(groups);
You can reassign the original object with the temporary object just used for this, and continue with your business logic, which I believe is the one you are looking for.

Reverse Traverse a hierarchy

I have a hierarchy of objects that contain the parent ID on them. I am adding the parentId to the child object as I parse the json object like this.
public static fromJson(json: any): Ancestry | Ancestry[] {
if (Array.isArray(json)) {
return json.map(Ancestry.fromJson) as Ancestry[];
}
const result = new Ancestry();
const { parents } = json;
parents.forEach(parent => {
parent.parentId = json.id;
});
json.parents = Parent.fromJson(parents);
Object.assign(result, json);
return result;
}
Any thoughts on how to pull out the ancestors if I have a grandchild.id?
The data is on mockaroo curl (Ancestries.json)
As an example, with the following json and a grandchild.id = 5, I would create and array with the follow IDs
['5', '0723', '133', '1']
[{
"id": "1",
"name": "Deer, spotted",
"parents": [
{
"id": "133",
"name": "Jaime Coldrick",
"children": [
{
"id": "0723",
"name": "Ardys Kurten",
"grandchildren": [
{
"id": "384",
"name": "Madelle Bauman"
},
{
"id": "0576",
"name": "Pincas Maas"
},
{
"id": "5",
"name": "Corrie Beacock"
}
]
},
There is perhaps very many ways to solve this, but in my opinion the easiest way is to simply do a search in the data structure and store the IDs in inverse order of when you find them. This way the output is what you are after.
You could also just reverse the ordering of a different approach.
I would like to note that the json-structure is a bit weird. I would have expected it to simply have nested children arrays, and not have them renamed parent, children, and grandchildren.
let data = [{
"id": "1",
"name": "Deer, spotted",
"parents": [
{
"id": "133",
"name": "Jaime Coldrick",
"children": [
{
"id": "0723",
"name": "Ardys Kurten",
"grandchildren": [
{
"id": "384",
"name": "Madelle Bauman"
},
{
"id": "0576",
"name": "Pincas Maas"
},
{
"id": "5",
"name": "Corrie Beacock"
}
]
}]
}]
}]
const expectedResults = ['5', '0723', '133', '1']
function traverseInverseResults(inputId, childArray) {
if(!childArray){ return }
for (const parent of childArray) {
if(parent.id === inputId){
return [parent.id]
} else {
let res = traverseInverseResults(inputId, parent.parents || parent.children || parent.grandchildren) // This part is a bit hacky, simply to accommodate the strange JSON structure.
if(res) {
res.push(parent.id)
return res
}
}
}
return
}
let result = traverseInverseResults('5', data)
console.log('results', result)
console.log('Got expected results?', expectedResults.length === result.length && expectedResults.every(function(value, index) { return value === result[index]}))

Search deep nested

I am working on a solution where I need to search for an element in a deeply nested JSON by its id. I have been advised to use underscore.js which I am pretty new to.
After reading the documentation http://underscorejs.org/#find , I tried to implement the solution using find, filter and findWhere.
Here is what I tried using find :
var test = {
"menuInputRequestId": 1,
"catalog":[
{
"uid": 1,
"name": "Pizza",
"desc": "Italian cuisine",
"products": [
{
"uid": 3,
"name": "Devilled chicken",
"desc": "chicken pizza",
"prices":[
{
"uid": 7,
"name": "regular",
"price": "$10"
},
{
"uid": 8,
"name": "large",
"price": "$12"
}
]
}
]
},
{
"uid": 2,
"name": "Pasta",
"desc": "Italian cuisine pasta",
"products": [
{
"uid": 4,
"name": "Lasagne",
"desc": "chicken lasage",
"prices":[
{
"uid": 9,
"name": "small",
"price": "$10"
},
{
"uid": 10,
"name": "large",
"price": "$15"
}
]
},
{
"uid": 5,
"name": "Pasta",
"desc": "chicken pasta",
"prices":[
{
"uid": 11,
"name": "small",
"price": "$8"
},
{
"uid": 12,
"name": "large",
"price": "$12"
}
]
}
]
}
]
};
var x = _.find(test, function (item) {
return item.catalog && item.catalog.uid == 1;
});
And a Fiddle http://jsfiddle.net/8hmz0760/
The issue I faced is that these functions check the top level of the structure and not the nested properties thus returning undefined. I tried to use item.catalog && item.catalog.uid == 1; logic as suggested in a similar question Underscore.js - filtering in a nested Json but failed.
How can I find an item by value by searching the whole deeply nested structure?
EDIT:
The following code is the latest i tried. The issue in that is that it directly traverses to prices nested object and tries to find the value. But my requirement is to search for the value in all the layers of the JSON.
var x = _.filter(test, function(evt) {
return _.any(evt.items, function(itm){
return _.any(itm.outcomes, function(prc) {
return prc.uid === 1 ;
});
});
});
Here's a solution which creates an object where the keys are the uids:
var catalogues = test.catalog;
var products = _.flatten(_.pluck(catalogues, 'products'));
var prices = _.flatten(_.pluck(products, 'prices'));
var ids = _.reduce(catalogues.concat(products,prices), function(memo, value){
memo[value.uid] = value;
return memo;
}, {});
var itemWithUid2 = ids[2]
var itemWithUid12 = ids[12]
I dont use underscore.js but you can use this instead
function isArray(what) {
return Object.prototype.toString.call(what) === '[object Array]';
}
function find(json,key,value){
var result = [];
for (var property in json)
{
//console.log(property);
if (json.hasOwnProperty(property)) {
if( property == key && json[property] == value)
{
result.push(json);
}
if( isArray(json[property]))
{
for(var child in json[property])
{
//console.log(json[property][child]);
var res = find(json[property][child],key,value);
if(res.length >= 1 ){
result.push(res);}
}
}
}
}
return result;
}
console.log(find(test,"uid",4));

Categories

Resources