filter value from array (object) react - javascript

I'm learning by coding, here i have 'allNodes' an array of objects and 'currentNodee' object, i want to check if allNodes contains 'analyser' and 'id' which is equal to 'analyser' and 'id' of 'currentNodee' then take 'analyser' value and print it, but if for example 'allNodes' has same id but its analyser is 'undefined' then do not print anything.
what am i doing wrong here ? any idea is appreciated
const allNodes = [
{ analyser: undefined, id: 7 },
{ analyser: "abc", id: 6 },
];
const currentNodee = { analyser: "abc", id: 7 };
console.log(
allNodes.find((option: any) => {
option.id === currentNodee.id &&
option?.analyser === currentNodee?.analyser;
})
);
English is not my mother language so could be mistakes.

Presented below is one possible way to achieve the desired objective.
Code Snippet
const rd = document.getElementById("rd");
const btn = document.getElementById("myBtn");
const btn2 = document.getElementById("myBtn2");
const allNodes = [{
analyser: undefined,
id: 7
},
{
analyser: "abc",
id: 6
},
];
const currentNodee = {
analyser: "abc",
id: 7
};
const currentNodef = {
analyser: "abc",
id: 6
};
const getResult = (curr) => {
const tgt = allNodes.find(
({ analyser, id }) => curr.id === id
);
if (tgt) {
if (
tgt.analyser &&
tgt.analyser === curr.analyser
) {
return JSON.stringify(tgt);
} else {
return "print nothing";
}
} else {
return "not found"
};
};
btn.textContent = 'Search analyser id=7';
btn.addEventListener('click', () => {
rd.innerText = getResult(currentNodee);
});
btn2.textContent = 'Search analyser id=6';
btn2.addEventListener('click', () => {
rd.innerText = getResult(currentNodef);
});
<div>
Search result: <div id="rd">empty</div>
<button id="myBtn" />
<button id="myBtn2" />
</div>
Printing in single line can be done using JSON.stringify() as demonstrated in the above code snippet.

const allNodes = [
{ analyser: undefined, id: 7 },
{ analyser: "abc", id: 6 },
];
const currentNodee = { analyser: "abc", id: 7 };
const result = allNodes.find(node => (node.analyser === currentNodee.analyser) && (node.id === currentNodee.id))
console.log(!result ? 'No result found' : result);

Related

TypeError: arr.map is not a function in js, and nextjs

I am getting this error, but the code was working now it's not working somehow.
TypeError: arr.map is not a function
Am I doing something wrong?
export const footerAdapter = (footerData) => {
const arr = footerData[0].attributes['items']
return arr.map((md) => {
return {
link: md.link,
title: md.title
};
});
};
Update:
I am trying yo fetch this data:
[
{
"attributes": {
"items": {
"title": "Hello world",
"link": "/Home",
"__typename": "ComponentFooterFooterItems"
},
"__typename": "Footer"
},
"__typename": "FooterEntity"
},
]
The "TypeError: map is not a function" occurs when we call the map() method on an object that is not an array.
To solve the error, console.log the value you're calling the map() method on and make sure to only call the map method on valid arrays.
const obj = {};
// ⛔️ Uncaught TypeError: map is not a function
const result = obj.map(element => {
return element + 1;
});
You can conditionally check if the value is an array by using the Array.isArray method.
const arr = 'test';
const result = Array.isArray(arr) ? arr.map(element => element + 1) : [];
console.log(result); // 👉️ []
Your data could be undefined or null and therefor it gives you an error. So you should write in a fallback:
export const footerAdapter = (footerData) => {
if (!footerData || !footerData[0] || !footerData[0].attributes || !footerData[0].attributes['items'] || footerData[0].attributes['items'].length <= 0) return []
const arr = footerData[0].attributes['items'];
return arr.map((md) => {
return {
link: md.link,
title: md.title
};
});
};
This will return an empty array if footerData[0].attributes['items'] is undefined or null;
Edit
The .map wont work because your 'items' isnt an array. If something has changed, this is what is wrong.
But you can change it to
export const footerAdapter = (footerData) => {
if (!footerData || !footerData[0] || !footerData[0].attributes || !footerData[0].attributes['items'] || footerData[0].attributes['items']) return {link: '', title: ''}
const obj = footerData[0].attributes['items']
return {
link: obj.link,
title: obj.title
}
}
Edit 2
If items for some reason sometimes are an array and sometimes are an object, you need to do some typechecking. One way to solve it is to:
export const footerAdapter = (footerData) => {
if (!footerData || !footerData[0] || !footerData[0].attributes || !footerData[0].attributes['items']) {
return [{link: '', title: ''}];
}
const arr = footerData[0].attributes['items'];
if (arr && arr[0] && arr.length > 0) {
return arr.map((md) => {
return {
link: md.link,
title: md.title
};
});
} else if (arr && arr.link && arr.title) {
return [{link: arr.link, title: arr.title}];
} else {
return [{link: '', title: ''}]
}
};
The above code is a litle ugly, but should work both if your items property is an array (like before) or an object in your example. With an handler which returns [{link: '', title: ''}] doesn't mach one of the two first strucktures.
try fixing the error using arr?.map
You can use the optional chaining
Note your items is not an array so we need more code
Here I use reduce, assuming that by [0] you only want the first entry in your array
const footerAdapter = footerData => Object.entries(footerData?.[0].attributes?.['items'] ?? {})
.filter(([key,value])=> ["link","title"].includes(key))
.reduce((acc, [key,value])=> (acc[key] = value, acc),{});
const fd1 = [{
"attributes": {
"items": {
"title": "Hello world",
"link": "/Home",
"__typename": "ComponentFooterFooterItems"
},
"__typename": "Footer"
},
"__typename": "FooterEntity"
} ];
const fd2 = [{
attributes: {}
}]
const arr1 = footerAdapter(fd1)
console.log(arr1)
const arr2 = footerAdapter(fd2)
console.log(arr2)
Array of objects
const footerAdapter = footerData => Object.entries(footerData?.[0].attributes?.['items'] ?? {})
.filter(([key,value])=> ["link","title"].includes(key))
.map(([key,value])=> ({[key]:value}));
const fd1 = [{
"attributes": {
"items": {
"title": "Hello world",
"link": "/Home",
"__typename": "ComponentFooterFooterItems"
},
"__typename": "Footer"
},
"__typename": "FooterEntity"
} ];
const fd2 = [{
attributes: {}
}]
const arr1 = footerAdapter(fd1)
console.log(arr1)
const arr2 = footerAdapter(fd2)
console.log(arr2)

Get last item active name on the list

How can i have the last item on the list where the case it is success?
children: [
{
case: "no-success",
name: "bruno",
endOffset: 5
},
{
case: "no-success",
name: "pippo",
endOffset: 5
}
{
case: "success",
name: "jo",
endOffset: 5
},
{
case: "success",
name: "Matteo",
endOffset: 5
},
{
case: "np-success",
name: "Robert",
endOffset: 5
}
]
I need to have the item where the name is Matteo.
Example for have the first i do : var foundIdx = this.newListWords[i].children.find(item => item.case === 'success').
Definition:
The find() method returns the FIRST element in the provided array that
satisfies the provided testing function. If no values satisfy the
testing function, undefined is returned.
You can reverse array:
this.newListWords[i].children.reverse().find(item => item.case === 'success')
Or you can use filter and get last child
const filtered = this.newListWords[i].children.filter(item => item.case === 'success')
const lastFind = filtered[filtered.length-1]
function lastSuccess(list: any[]): any {
const SUCCESS_STRING = 'success';
const [lastItem] = list // Take the list's head
.filter(o => o.success === SUCCESS_STRING) // Filter for success
.reverse(); // Reverse the list
return lastItem;
}
const item = lastSuccess(this.newListWords[i].children);
var children = [
{
case: "no-success",
name: "bruno",
endOffset: 5
},
{
case: "no-success",
name: "pippo",
endOffset: 5
},
{
case: "success",
name: "jo",
endOffset: 5
},
{
case: "success",
name: "Matteo",
endOffset: 5
},
{
case: "np-success",
name: "Robert",
endOffset: 5
}
];
function getLastSuccess(children) {
if (!Array.isArray(children)) {
return {};
}
for (var i = children.length - 1, o; o = children[i]; i--) {
if (o.case === 'success') {
return o;
}
}
}
console.log(getLastSuccess(children));
Single line code
let v = children.reduce((s, c) => { if (c.case === "success") { return c } else { return s } }, null);
You will get null if there is no success.
This should find the last item in the filtered array with 'success',
children.findLast(item => item.case === 'success')

React.js: How to find duplicates for properties in an array of object and put a progressive number on that field

I have an array of object and each object is for example :
const myArr=[{name:"john",id:1}{name:"john",id:2}{name:"mary",id:3}]
for the first 2 element for the property "name" I have the name "john" that is duplicate.
How can I modify the rendered names like that:
const myArr=[{name:"john (1 of 2)",id:1}{name:"john (2 of 2)",id:2}{name:"mary",id:3}]
Thanks in advance!
Reduce the input array into a map by name (i.e. group by name property), and map the array of values to the result array. If the group array has more than 1 element in it then sub-map the group to include the numbering. Flatten the overall result.
const myArr = [
{ name: "john", id: 1 },
{ name: "john", id: 2 },
{ name: "mary", id: 3 }
];
const res = Object.values(
myArr.reduce((groups, current) => {
if (!groups[current.name]) {
groups[current.name] = [];
}
groups[current.name].push(current);
return groups;
}, {})
).flatMap((value) => {
if (value.length > 1) {
return value.map((current, i, arr) => ({
...current,
name: `${current.name} (${i + 1} of ${arr.length})`
}));
}
return value;
});
console.log(res);
You can do use reduce(), filter(), and flat() and do this:
const myArr = [
{name:"john", id:1},
{name:"john", id:2},
{name:"mary", id:3}
]
const res = Object.values(myArr.reduce((acc, curr) => {
const total = myArr.filter(({ name }) => name === curr.name).length;
if(!acc[curr.name]) {
acc[curr.name] = [
{...curr}
]
} else {
const currentSize = acc[curr.name].length;
if(currentSize === 1) {
acc[curr.name][0].name = `${acc[curr.name][0].name} (1 of ${total})`
}
acc[curr.name].push({
...curr,
name: `${curr.name} (${currentSize + 1} of ${total})`
})
}
return acc;
}, {})).flat();
console.log(res);
const myArr = [{name:"john",id:1}, {name:"john",id:2}, {name:"mary",id:3}];
const namesArray = myArr.map(elem => elem.name);
const namesTraversed = [];
let currentCountOfName = 1;
let len = 0;
myArr.forEach(elem => {
len = namesArray.filter(name => name === elem.name).length;
if (len > 1) {
if (namesTraversed.includes(elem.name)) {
namesTraversed.push(elem.name);
currentCountOfName = namesTraversed.filter(name => name === elem.name).length;
elem.name = `${elem.name} (${currentCountOfName} of ${len})`;
} else {
namesTraversed.push(elem.name);
currentCountOfName = 1;
elem.name = `${elem.name} (${currentCountOfName} of ${len})`;
}
}
});
console.log(myArr);
Check if this helps you
const myArr = [{
name: "john",
id: 1
}, {
name: "john",
id: 2
}, {
name: "mary",
id: 3
}]
// to keep a track of current copy index
let nameHash = {}
const newMyArr = myArr.map(ele => {
const noOccurence = myArr.filter(obj => obj.name ===ele.name).length;
if(noOccurence > 1){
// if there are multiple occurences get the current index. If undefined take 1 as first copy index.
let currentIndex = nameHash[ele.name] || 1;
const newObj = {
name: `${ele.name} (${currentIndex} of ${noOccurence})`,
id: ele.id
}
nameHash[ele.name] = currentIndex+ 1;
return newObj;
}
return ele;
})
console.log(newMyArr);

spread operator to copy values to nested object dynamically using array forEach loop

This is the code I made, its actually from the react project I am working on, where I wanted to add more key-value pairs under particular keys. So I made a similar sample code to know how to do it, but unfortunately, I can't find a solution on the internet.
Please help
const filteredSearchItems=[{
"id":"das",
"value":45
},
{
"id":"das3",
"value":48
},
{
"id":"das4",
"value":47
},
{
"id":"das5",
"value":46
},
]
let savedFilter = "";
const savefilter = () => {
const saveName = "fooCriteria";
filteredSearchItems.forEach(item => {
if (!savedFilter) {
savedFilter={ [saveName]: { [item.id]: item.value } };
} else
savedFilter={...savedFilter.saveName,...{
...savedFilter.saveName,
...{ [item.id]: item.value }
}};
});
};
savefilter();
console.log("savedFilter :",savedFilter)
output
savedFilter : { das5: 46 }
My Expected output that I wanted
{ fooCriteria: { das: 45, das3: 48, das4: 47, das5: 46 } }
PS: I wanted to give fooCriteria as savename variable there is a reason. since the name of the object is determined by the user
const saveName = document.getElementById("seachSaveInput").value;
const filteredSearchItems=[{"id":"das","value":45},{"id":"das3","value":48},{"id":"das4","value":47},{"id":"das5","value":46}];
let fooCriteria = filteredSearchItems.reduce((acc,{id,value})=>(acc[id]=value,acc),{});
console.log({fooCriteria})
You can use reduce method
instead of forEach reduce makes more sense.
const filteredSearchItems = [
{
'id': 'das',
'value': 45
},
{
'id': 'das3',
'value': 48
},
{
'id': 'das4',
'value': 47
},
{
'id': 'das5',
'value': 46
}
];
const savedFilter = {};
const saveFilter = () => {
const saveName = 'fooCriteria';
savedFilter[saveName] = filteredSearchItems.reduce((saved, item) => {
saved[item.id] = item.value;
return saved;
}, savedFilter[saveName] || {});
};
saveFilter();
console.log('savedFilter :', savedFilter);
I'd do a shallow copy with spread notation:
// If you want to add to the [saveName] entry if it exists:
savedFilter = {...savedFilter, [saveName]: savedFilter ? {...savedFilter[saveName]} : {}};
// If you want to *replace* the [saveName] entry, not add to it:
savedFilter = {...savedFilter, [saveName]: {}};
then update the result with a loop:
for (const {id, value} of filteredSearchItems) {
savedFilter[saveName][id] = value;
}
Here's an example assuming you want to replace the [saveName] property if it exists:
const filteredSearchItems=[{
"id":"das",
"value":45
},
{
"id":"das3",
"value":48
},
{
"id":"das4",
"value":47
},
{
"id":"das5",
"value":46
},
];
let savedFilter = {somethingAlreadyThere: 42};
const saveName = "fooCriteria";
savedFilter = {...savedFilter, [saveName]: {}};
for (const {id, value} of filteredSearchItems) {
savedFilter[saveName][id] = value;
}
console.log(savedFilter);
There are other, more complicated ways (reduce, map and Object.fromEntries, ...), but they don't have any advantage over the simple, straightfoward loop.
That said, the map and Object.fromEntries version is really concise, if that's your thing:
// Assumes you want to replace the [saveName] property entirely
const saveName = "fooCriteria";
savedFilter = {
...savedFilter,
[saveName]: Object.fromEntries(filteredSearchItems.map(({id, value}) => [id, value]))
};
const filteredSearchItems=[{
"id":"das",
"value":45
},
{
"id":"das3",
"value":48
},
{
"id":"das4",
"value":47
},
{
"id":"das5",
"value":46
},
];
let savedFilter = {somethingAlreadyThere: 42};
const saveName = "fooCriteria";
savedFilter = {
...savedFilter,
[saveName]: Object.fromEntries(filteredSearchItems.map(({id, value}) => [id, value]))
};
console.log(savedFilter);
Don't be fooled, though, there's a loop in there (actually two of them, one for map, the other for fromEntries). :-)
Using ...spread operator you can do it something like this:
const filteredSearchItems = [{
"id": "das",
"value": 45
},
{
"id": "das3",
"value": 48
},
{
"id": "das4",
"value": 47
},
{
"id": "das5",
"value": 46
},
]
let savedFilter = "";
const savefilter = () => {
const saveName = "fooCriteria";
let res = {};
filteredSearchItems.forEach(item => {
if (!savedFilter) {
savedFilter = { [saveName]: { [item.id]: item.value } };
} else
savedFilter[saveName] = {
...{ [item.id]: item.value }, ...savedFilter[saveName]
}
});
};
savefilter();
console.log("savedFilter :", savedFilter.fooCriteria)
const filteredSearchItems=[{
"id":"das",
"value":45
},
{
"id":"das3",
"value":48
},
{
"id":"das4",
"value":47
},
{
"id":"das5",
"value":46
},
]
var a1={};
for(let i=0 ; i<filteredSearchItems.length;i++){
let id1 = filteredSearchItems[i].id;
let id2 = filteredSearchItems[i].value;
a1[id1] = id2;
}
var t2 = {"fooCriteria": a1}
console.log(JSON.stringify(t2));
Output : {"njkcnv":{"das":45,"das3":48,"das4":47,"das5":46}}

Remove parent object and child object if value is undefined using Array.filter(?)

Question:
How can I removal all emailAddress that are empty, and if there are no emailAddresses for an approval, remove that approval too.
My current solution will remove approvals when emailAddress completely empty. But not when two emailAddresses are present and one is empty (see script output vs. expected output)
var request = {
approvals: [
{
type: 'media',
emailAddresses: [
{emailAddress: 'frank#gmail.com'},
]
},
{
type: 'other',
emailAddresses: [
{emailAddress: ''},
]
},
{
type: 'scope',
emailAddresses: [
{emailAddress: 'kelly#yahoo.com'},
{emailAddress: ''},
]
}
]
}
const filterOutEmptyEmails = (approval) => {
if(approval.emailAddresses.filter(x => !!x.emailAddress).length){
return true;
}
}
let output = request.approvals.filter(filterOutEmptyEmails);
console.log(JSON.stringify(output));
// EXPECTED OUTPUT:
// approval: [
// {
// type: 'media',
// emailAddresses: [
// {emailAddress: 'frank#gmail.com'},
// ]
// },
// {
// type: 'scope',
// emailAddresses: [
// {emailAddress: 'kelly#yahoo.com'},
// ]
// }
// ]
// }]
Live Code
You are not replacing approval.emailAddresses in your code - you should use:
approval.emailAddresses = approval.emailAddresses.filter(x => !!x.emailAddress);
See demo below:
var request={approvals:[{type:'media',emailAddresses:[{emailAddress:'frank#gmail.com'},]},{type:'other',emailAddresses:[{emailAddress:''},]},{type:'scope',emailAddresses:[{emailAddress:'kelly#yahoo.com'},{emailAddress:''},]}]};
var filterOutEmptyEmails = (approval) => {
approval.emailAddresses = approval.emailAddresses.filter(x => !!x.emailAddress);
if(approval.emailAddresses.length){
return true;
}
}
var output = request.approvals.filter(filterOutEmptyEmails);
console.log(JSON.stringify(output));
EDIT:
Another proposal without mutating the input array - using Array.prototype.reduce to create a new array:
var request={approvals:[{type:'media',emailAddresses:[{emailAddress:'frank#gmail.com'},]},{type:'other',emailAddresses:[{emailAddress:''},]},{type:'scope',emailAddresses:[{emailAddress:'kelly#yahoo.com'},{emailAddress:''},]}]};
var output = request.approvals.reduce(function(p,c){
// creates a shallow copy
var elem = Object.assign({},c);
// replaces the reference to request.approvals by the new array created by the filter
elem.emailAddresses = elem.emailAddresses.filter(x => !!x.emailAddress);
if(elem.emailAddresses.length != 0)
p.push(elem);
return p;
},[]);
// console.log(request.approvals);
console.log(output);
.as-console-wrapper{top:0;max-height:100%!important;}
Possible "non mutation" solution could be like this
var request = {approvals: [{type: 'media',emailAddresses: [{emailAddress: 'frank#gmail.com'},]},{type: 'other',emailAddresses: [{emailAddress: ''},]},{type: 'scope', emailAddresses: [{emailAddress: 'kelly#yahoo.com'},{emailAddress: ''},]}]}
const filterOutEmptyEmails = (approval) => {
if(approval.emailAddresses.filter(x => !!x.emailAddress).length){
return true;
}
}
const output = request.approvals.map(approval => {
const filteredAproval = approval;
filteredAproval.emailAddresses = approval.emailAddresses.filter(x => !!x.emailAddress);
return filteredAproval
}).filter(filterOutEmptyEmails);
console.log(JSON.stringify(output));
console.log(JSON.stringify(request));
Without mutation (with lots of ES6/7 sugar):
const filteredApprovals = request.approvals.reduce((acc, approval) => {
const filteredEmailAddresses = approval.emailAddresses.filter(item => item.emailAddress);
return (filteredEmailAddresses.length > 0) ? [...acc, { ...approval, emailAddresses: filteredEmailAddresses }] : acc;
}, []);
Fiddle: https://jsfiddle.net/free_soul/hndjbce3/

Categories

Resources