Filter function with 2 array sets - javascript

I am trying to achieve the same result as i wrote in below syntax by implementing filter function to my script.
The current script i have
let sheet = [
{ $0: { 'Name': 'Report1' } },
{ $0: { 'Name': 'Row Count' } },
{ $0: { 'Name': 'Report2' } },
{ $0: { 'Name': 'User' } }
]
let nope = ['User','Row Count','Container']
let result = []
for(let i = 0; i < sheet.length ;i++){
if(sheet[i].$0.Name != nope[0] && sheet[i].$0.Name != nope[1] && sheet[i].$0.Name != nope[2]){
result.push(sheet[i])
}
}
console.log(result)
On my browser inspect element, it will result of (2) [{…}, {…}] on console.log
I tried using filter function
let result_2 = sheet.filter(w => !w.$0.Name.includes(nope[0]))
console.log(result_2)
1 : One problem and logic i face is that im unsure on how can i includes all the element of 'nope' in 'includes()'
2 : I will have to hard code the index such as nope[0] which i dont think is advisable if its going to be a big array

You actually almost finish but you reverse the w.$0.Name and nope.
let sheet = [
{ $0: { Name: "Report1" } },
{ $0: { Name: "Row Count" } },
{ $0: { Name: "Report2" } },
{ $0: { Name: "User" } },
];
let nope = ["User", "Row Count", "Container"];
let result_2 = sheet.filter(w => !nope.includes(w.$0.Name));
console.log(result_2);
PS: I think you should take a break and drink some tea. :)

let result_2 = sheet.filter(w => !nope.includes(w.$0.Name))

A simple and alternativr solution would be to use every() method within the filter. Like this:
It will check one element for every case of the second array and return true if nothing similar would be found.
let result_2 = sheet.filter(w => nope.every(x=> x !== w.$0.Name))
console.log(result_2)
let sheet = [{
$0: {
'Name': 'Report1'
}
},
{
$0: {
'Name': 'Row Count'
}
},
{
$0: {
'Name': 'Report2'
}
},
{
$0: {
'Name': 'User'
}
}
]
let nope = ['User', 'Row Count', 'Container']
let result = []
let result_2 = sheet.filter(w => nope.every(x => x !== w.$0.Name))
console.log(result_2)
Or if you want to use includes() you can do this:
let result_3 = sheet.filter(w => !nope.includes(w.$0.Name))
console.log(result_2)
let sheet = [{
$0: {
'Name': 'Report1'
}
},
{
$0: {
'Name': 'Row Count'
}
},
{
$0: {
'Name': 'Report2'
}
},
{
$0: {
'Name': 'User'
}
}
]
let nope = ['User', 'Row Count', 'Container']
let result = []
let result_3 = sheet.filter(w => !nope.includes(w.$0.Name))
console.log(result_2)
Fiddle example

Related

How to check if a value in an array is present in other object and accordingly return a new object

I have an array
const dataCheck = ["Rohit","Ravi"];
I have another array of object
const userData = [
{ name: "Sagar" },
{ name: "Vishal" },
{ name: "Rohit" },
{ name: "Ravi" },
];
I want to check if any value in dataCheck is present in the userData and then return a new array with the below data
const newData = [
{ name: "Sagar" },
{ name: "Vishal" },
{ name: "Rohit", status: "present" },
{ name: "Ravi", status: "present" },
];
I tried to do something using loops but not getting the expected results
const dataCheck = ["Rohit", "Ravi"];
const userData = [
{ name: "Sagar" },
{ name: "Vishal" },
{ name: "Rohit" },
{ name: "Ravi" }
];
let newDataValue = {};
let newData = [];
userData.forEach((user) => {
const name = user.name;
dataCheck.forEach((userName) => {
if (name === userName) {
newDataValue = {
name: name,
status: "present"
};
} else {
newDataValue = {
name: name
};
}
newData.push(newDataValue);
});
});
console.log(newData);
My trial gives me repeated results multiple results which is just duplicates
You should use map() and a Set.
const dataCheck = ["Rohit","Ravi"];
const userData = [
{ name: "Sagar" },
{ name: "Vishal" },
{ name: "Rohit" },
{ name: "Ravi" },
];
const set = new Set(dataCheck);
const output = userData.map(data => set.has(data.name) ? ({...data, status: "present"}): data)
console.log(output)
.as-console-wrapper { max-height: 100% !important; top: 0; }
A Set allows for lookups in O(1) time and therefore this algorithm works in O(n) time. If you would use the array for lookups (e.g. using indcludes(), find() etc.) the runtime would be O(n²). Although this will certainly not matter at all for such small arrays, it will become more relevant the larger the array gets.
map() is used here because you want a 1:1 mapping of inputs to outputs. The only thing to determine then is, what the output should be. It is either the input, if the value is not in the Set, or it is the input extended by one property status set to "present". You can check for the presence in a Set using the has() method and can use the ternary operator ? to make the decision which case it is.
const dataCheck = ["Rohit", "Ravi"];
const userData = [
{ name: "Sagar" },
{ name: "Vishal" },
{ name: "Rohit" },
{ name: "Ravi" },
];
// map through every object and check if name property
// exists in data check with help of filter.
// if it exists the length of filter should be 1 so
// you should return { name: el.name, status: "present" } else
// return { name: el.name }
let newData = userData.map((el) => {
if (dataCheck.filter((name) => name === el.name).length > 0) {
return { name: el.name, status: "present" };
} else {
return { name: el.name };
}
});
console.log("newdata: ", newData);
A better approach would be to use map over userData array, find for matching element in dataCheck, if found return matching element + a status key or just return the found element as it is.
const dataCheck = ["Rohit","Ravi"];
const userData = [
{ name: "Sagar" },
{ name: "Vishal" },
{ name: "Rohit" },
{ name: "Ravi" },
];
const getUpdatedObject = () => {
return userData.map(userData => {
const userDetail = dataCheck.find(data => userData.name === data);
if(userDetail) return {userDetail, status:"present"}
else return {...userData}
});
}
console.log(getUpdatedObject())
Working fiddle
Loop through userData, check if name is includes in dataCheck. If true add status 'present'.
const dataCheck = ["Rohit","Ravi"];
const userData = [
{ name: "Sagar" },
{ name: "Vishal" },
{ name: "Rohit" },
{ name: "Ravi" },
];
for (let user of userData) {
if(dataCheck.includes(user.name)) {
user.status = 'present'
}
}
console.log(userData)
You are seeing repeated results due to the second loop dataCheck.forEach((userName) => { as every loop of dataCheck will fire the if/else statement and add something to the final array. However many values you add to dataCheck will be however many duplicates you get.
Only need to loop through one array and check if the value is in the other array so no duplicates get added.
const dataCheck = ["Rohit", "Ravi"];
const userData = [{ name: "Sagar" }, { name: "Vishal" }, { name: "Rohit" }, { name: "Ravi" }];
let newDataValue = {};
let newData = [];
// loop thru the users
userData.forEach((user) => {
// set the user
const name = user.name;
// check if in array
if (dataCheck.indexOf(name) >= 0) {
newDataValue = {
name: name,
status: "present",
};
}
// not in array
else {
newDataValue = {
name: name,
};
}
newData.push(newDataValue);
});
console.log(newData);
So you will do like this :
const dataCheck = ["Rohit","Ravi"];
const userData = [
{ name: "Sagar" },
{ name: "Vishal" },
{ name: "Rohit" },
{ name: "Ravi" },
];
const newUserData = userData.map( user => {
dataCheck.forEach( data => {
if( data === user.name )
user.status = "present";
});
return user;
} );
console.log( newUserData );

Updating JSON structure based on id

I was trying to update the town name in the below-given JSON structure.
"City":[
{
"Name":"Delhi",
"id":"c5d58bef-f1c2-4b7c-a6d7-f64df12321bd",
"Towns":[
{
"Name":"MG Colony",
"conditionId":"60d1f5eb-0222-4a84-879b-6699b0cfc1a4",
"cid":"c5d58bef-f1c2-4b7c-a6d7-f64df12321bd"
},
{
"Name":"DLF Colony",
"conditionId":"60d1f5eb-0222-4a84-879b-7749b0cfc1a4",
"cid":"c5d58bef-f1c2-4b7c-a6d7-f64df12321bd"
}
]
},
{
"Name":"Pune",
"id":"c5d58bef-f1c2-4b7c-a6d7-f64df12321ax",
"Towns":[
{
"Name":"Hadapsar",
"conditionId":"60d1f5eb-0222-4a84-879b-6699b0cfc1x4",
"cid":"c5d58bef-f1c2-4b7c-a6d7-f64df12321ax"
},
{
"Name":"Magarpatta",
"conditionId":"60d1f5eb-0222-4a84-879b-7749b0cfc1f4",
"cid":"c5d58bef-f1c2-4b7c-a6d7-f64df12321bax"
}
]
}
]
I wanted to change the town name from "Hapdasar" to "Viman Nagar" if my cid matches that of Hadapsar Town
Output which I wanted was:
"City":[
{
"Name":"Delhi",
"id":"c5d58bef-f1c2-4b7c-a6d7-f64df12321bd",
"Towns":[
{
"Name":"MG Colony",
"conditionId":"60d1f5eb-0222-4a84-879b-6699b0cfc1a4",
"cid":"c5d58bef-f1c2-4b7c-a6d7-f64df12321bd"
},
{
"Name":"DLF Colony",
"conditionId":"60d1f5eb-0222-4a84-879b-7749b0cfc1a4",
"cid":"c5d58bef-f1c2-4b7c-a6d7-f64df12321bd"
}
]
},
{
"Name":"Pune",
"id":"c5d58bef-f1c2-4b7c-a6d7-f64df12321ax",
"Towns":[
{
"Name":"Viman Nagar",
"conditionId":"60d1f5eb-0222-4a84-879b-6699b0cfc1x4",
"cid":"c5d58bef-f1c2-4b7c-a6d7-f64df12321ax"
},
{
"Name":"Magarpatta",
"conditionId":"60d1f5eb-0222-4a84-879b-7749b0cfc1f4",
"cid":"c5d58bef-f1c2-4b7c-a6d7-f64df12321bax"
}
]
}
]
I was using js map to iterate but was confused about how to replicate the exact structure.
Well, map alone is not enough to solve your problem, since you have two nested arrays. Maybe you can consider the possibility to use maptwice?
For example:
var cid = "c5d58bef-f1c2-4b7c-a6d7-f64df12321ax";
var newName = "Viman Nagar";
City = City.map(function(city) {
city.towns = city.towns.map(function(town) {
if (town.cid === cid)
town.name = newName;
return town;
});
return city;
});
Atribute your object for
let cities = [{
"Name": "Delhi"
...
}]
and then you can map over it
let result = cities.map(city => city.Towns.map(town => {
if (town.Name === "Hadapsar") {
return {
...town,
Name: "Viman Nagar"
}
} else return town
}))
Use Array#map as follows:
Iterate over cities
In every iteration, iterate over Towns. If current town's cid is equal to the one to change, update its Name
const changeTownName = (cities = [], cid, name) =>
cities.map(({ Towns = [], ...props }) => ({
...props,
Towns: Towns.map(town => town.cid === cid
? { ...town, Name: name }
: { ...town }
)
}));
const cities = [
{ Name: 'Delhi', id: 'c5d58bef-f1c2-4b7c-a6d7-f64df12321bd', Towns: [ { Name: "MG Colony", conditionId: '60d1f5eb-0222-4a84-879b-6699b0cfc1a4', cid: 'c5d58bef-f1c2-4b7c-a6d7-f64df12321bd' }, { Name: "DLF Colony", conditionId: '60d1f5eb-0222-4a84-879b-7749b0cfc1a4', cid: 'c5d58bef-f1c2-4b7c-a6d7-f64df12321bd' } ] },
{ Name: 'Pune', id: 'c5d58bef-f1c2-4b7c-a6d7-f64df12321ax', Towns: [ { Name: "Hadapsar", conditionId: '60d1f5eb-0222-4a84-879b-6699b0cfc1x4', cid: 'c5d58bef-f1c2-4b7c-a6d7-f64df12321ax' }, { Name: "Magarpatta", conditionId: '60d1f5eb-0222-4a84-879b-7749b0cfc1f4', cid: 'c5d58bef-f1c2-4b7c-a6d7-f64df12321bax' } ] }
];
console.log( changeTownName(cities, 'c5d58bef-f1c2-4b7c-a6d7-f64df12321ax', 'Viman Nagar') );
If you consider city as cities this code can help you;
cities.forEach(city => {
city.Towns = city.Towns.map(el => {
if (el.Name === 'Hapdasar') {
el.Name = 'Viman Nagar';
}
return el;
})
});
You'll need to loop for each city in your array, and each town in the city. If the cid matches the town's cid, then change it;
const myNewTownName = "Viman Nagar";
const cid = "c5d58bef-f1c2-4b7c-a6d7-f64df12321ax";
for(let i = 0; i < myObj.City.length; i++){
const city = myObj.City[i];
for(let j = 0; j < city.Towns.length; j++){
const town = city.Towns[j];
if(cid === town.cid){
town.Name = myNewTownName;
}
city.town[j] = town;//Updates city with the updated town
}
myObj.City[i] = city; //Updates myObj with the updated city
}
The result can also be obtained using nested .forEach loops to parsing through the outer and inner arrays, with an if block to examine the cid for the target town.
const data = {
"City":[
{
"Name":"Delhi",
"id":"c5d58bef-f1c2-4b7c-a6d7-f64df12321bd",
"Towns":[
{
"Name":"MG Colony",
"conditionId":"60d1f5eb-0222-4a84-879b-6699b0cfc1a4",
"cid":"c5d58bef-f1c2-4b7c-a6d7-f64df12321bd"
},
{
"Name":"DLF Colony",
"conditionId":"60d1f5eb-0222-4a84-879b-7749b0cfc1a4",
"cid":"c5d58bef-f1c2-4b7c-a6d7-f64df12321bd"
}
]
},
{
"Name":"Pune",
"id":"c5d58bef-f1c2-4b7c-a6d7-f64df12321ax",
"Towns":[
{
"Name":"Hadapsar",
"conditionId":"60d1f5eb-0222-4a84-879b-6699b0cfc1x4",
"cid":"c5d58bef-f1c2-4b7c-a6d7-f64df12321ax"
},
{
"Name":"Magarpatta",
"conditionId":"60d1f5eb-0222-4a84-879b-7749b0cfc1f4",
"cid":"c5d58bef-f1c2-4b7c-a6d7-f64df12321bax"
}
]
}
]
} // end data;
const targetCid = "c5d58bef-f1c2-4b7c-a6d7-f64df12321ax"; // cid for Hadapsar;
const objArray = data.City;
objArray.forEach(element => {
element.Towns.forEach(element => {
if (element.cid == targetCid) {
element.Name = "Viman Nagar";
} // end if;
}); // next object in Towns array;
}); // next object in objArray;
document.getElementById('output').textContent = JSON.stringify(data, undefined, 2);
#output {
white-space: pre;
}
<pre id="output"></pre>

Find element in map

I have a map of objects:
"0": {
key: 'id',
value: {
name: "eval"
// other variables
}
},
"1": {
key: 'id',
value: {
name: "help"
// other variables
}
} // and so on
I need to find an element in map that's name variable is eqaul to "eval". What's the easiest way to do this?
If "map" is an array
let arr = [{key:'id', value:{ name:'eval' }}]
let item = arr.find(el => el.value.name == 'eval')
If "map" is an object
let obj = {0:{key:'id', value:{ name:'eval' }}}
let item = Object.values(obj).find(el => el.value.name == 'eval')
Use <Array>.from to convert map values to array and after filter what you want.
const map = new Map();
map.set(0, {
key: 'id',
value: {
name: "eval"
}
});
map.set(1, {
key: 'id',
value: {
name: "help"
}
});
const result = Array.from(map.values())
.filter(x => x.value.name === 'eval')[0];
console.log(result);
The good old forEach Loop can do it too.
const data = [{
key: 'id',
value: {
name: "eval"
// other variables
}
},
{
key: 'id',
value: {
name: "help"
// other variables
}
}]
let res = [];
data.forEach((el) => {
if (el.value.name === "eval") {
res.push(el);
}
})
console.log(res)
You can do this
const tmp = {
"0": {
key: "id",
value: {
name: "eval"
// other variables
}
},
"1": {
key: "id",
value: {
name: "eval"
// other variables
}
}
};
function findEval(obj, target) {
const elem = Object.keys(obj).filter(key => tmp[key].value.name === target);
return elem.map(e => obj[e]);
}
console.log(findEval(tmp, 'eval'))
but better use lodash Find property by name in a deep object
simple and best solution
const tmp = {
"0": {
key: "id",
value: {
name: "eval"
// other variables
}
},
"1": {
key: "id",
value: {
name: "eval"
// other variables
}
}
};
function findEval(obj, target) {
for (var i=0; i < Object.keys(obj).length; i++) {
if (obj[i].value.name === target) {
return obj[i].value.name;
}
}
}
console.log(findEval(tmp, 'eval'))

sort an array of object accoring to the values

I have this array of objects:
const array =[
{ a: 'good car' },
{ a: 'good car1' },
{ a: 'good car2' },
{ a: 'good car3' },
{ a: 'good car4' },
{ b: 'good car1' }
];
I need to sort it via values except in the case of ties. In the case of ties, the key is used to break the tie. I searched A LOT but couldn't use the answers as my keys in objects are not the same and also in case of the tie (values are the same), I cannot handle that.
Any suggestions?
You could get the entries, pick the first one and destructure it to key and value and take the same for the other object, then return the chained sorting values.
var array = [{ v21: 'sad sdd' }, { aaa: 'sad sdd' }, { v11: 'r err rr' }, { hf32: 'erwwer fgh' }, { z3f2: 'agfrr vbbar' }, { t142: 'gggoog anfa' }, { u23: 'fa handle err' }];
array.sort((a, b) => {
var [keyA, valueA] = Object.entries(a)[0],
[keyB, valueB] = Object.entries(b)[0];
return valueA.localeCompare(valueB) || keyA.localeCompare(keyB);
});
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }
use sort from es6.
try this code:
const array =[
{ v21: 'sad sdd' },
{ v11: 'r err rr' },
{ hf32: 'erwwer fgh' },
{ z3f2: 'agfrr vbbar' },
{ t142: 'agfrr vbbar' },
{ u23: 'fa handle err' }
]
array.sort( (x,y) => {
if ( Object.values(x)[0] > Object.values(y)[0] )
return 1
else if ( Object.values(x)[0] < Object.values(y)[0] )
return -1
else {
if ( Object.keys(x)[0] > Object.keys(y)[0] )
return 1
else if ( Object.keys(x)[0] < Object.keys(y)[0] )
return -1
}
})
You can try the following code:
const array =[
{ v21: 'sad sdd' },
{ v11: 'r err rr' },
{ hf32: 'erwwer fgh' },
{ z3f2: 'agfrr vbbar' },
{ z3f1: 'agfrr vbbar' },
{ t142: 'gggoog anfa' },
{ u23: 'fa handle err' }
];
array.sort((a,b) => {
if (a[Object.keys(a)[0]] === b[Object.keys(b)[0]]) {
return Object.keys(a)[0].localeCompare(Object.keys(b)[0]);
}
return a[Object.keys(a)[0]].localeCompare(b[Object.keys(b)[0]]);
});
console.log(array);
A variant without using compare function:
const array = [
{ v21: "sad sdd" },
{ v11: "r err rr" },
{ hf32: "erwwer fgh" },
{ z3f2: "sad sdd" },
{ t142: "gggoog anfa" },
{ u23: "fa handle err" }
];
const result = array
.map(item => ({
key: Object.keys(item)[0],
value: item[Object.keys(item)[0]]
}))
.map(item => `${item.value}:${item.key}`)
.sort()
.map(item => item.split(":"))
.map(item => ({ [item[1]]: item[0] }));
console.log(result);
have to use maybe some other join char instead of ':' if it is expected in the value

Looping through (possibly infinitely) repeating object structure

I have a problem I can't get my head around. If I am looking for an object with a certain ID in a possibly infinite data structure, how can I loop through it until I find the object I need and return that object?
If this is what my data looks like, how can I get the object with id === 3 ?
{
id: 0,
categories: [
{
id: 1,
categories: [
{
id: 2,
categories: [ ... ]
},
{
id: 3,
categories: [ ... ]
},
{
id: 4,
categories: [ ... ]
},
]
}
]
}
I tried the following:
findCategory = (categoryID, notesCategory) => {
if (notesCategory.id === categoryID) {
return notesCategory;
}
for (let i = 0; i < notesCategory.categories.length; i += 1) {
return findCategory(categoryID, notesCategory.categories[i]);
}
return null;
};
But that doesn't get ever get to id === 3. It checks the object with id: 2 and then returns null. It never gets to the object with id: 3.
Here is a JSbin: https://jsbin.com/roloqedeya/1/edit?js,console
Here is the case. when you go in to the first iteration of 'for' loop, because of the return call, the execution is go out from the function. you can check it by using an console.log to print the current object in the begin of your function.
try this
function find(obj, id) {
if(obj.id === id) {
console.log(obj) // just for testing. you can remove this line
return obj
} else {
for(var i = 0; i < obj.categories.length; i++) {
var res = find(obj.categories[i], id);
if(res) return res;
}
}
}
hope this will help you. thanks
You need to store the intermediate result and return only of the object is found.
function findCategory(object, id) {
var temp;
if (object.id === id) {
return object;
}
object.categories.some(o => temp = findCategory(o, id));
return temp;
}
var data = { id: 0, categories: [{ id: 1, categories: [{ id: 2, categories: [] }, { id: 3, categories: [] }, { id: 4, categories: [] }] }] }
result = findCategory(data, 3);
console.log(result);

Categories