Conditially using an object property - javascript

I have the following ternary:
exceptionType == 'Asset' ? selection = selectedAssets.find(function(obj) {return obj.fixedTitle === element}) : selection = dedupedAssets.find(function(obj) {return obj.fixedTitle === element});
I am conditionally assigning the variable selection to the value returned by find(). The functions are extremely similar, with the only difference being the array that is targeted.
Is there a way I can shorten this even further?

You could use the ternary operator to know what items to be iterated on and use the logic run once instead of duplicating it.
const itemsToIterate = exceptionType == 'Asset' ? selectedAssets : dedupedAssets;
const items = itemsToIterate.find(function(obj) {return obj.fixedTitle === element});
You can tweak this a bit to make it even shorter.
const itemsToIterate = exceptionType == 'Asset' ? selectedAssets : dedupedAssets;
const items = itemsToIterate.find(({ fixedTitle }) => fixedTitle === element);

You can use your boolean condition as an index to get the right array to apply find to:
const selection = [dedupedAssets, selectedAssets][+(exceptionType === 'Asset')]
.find(o => o.fixedTitle === element);
Using the operator +, false will be converted to 0 and dedupedAssets will be returned, and true will be converted to 1 and selectedAssets will be returned.
Indexing example
const a = [{ title: 'hello' }];
const b = [{ title: 'world' }];
console.log([a, b][+false].find(o => o.title === 'hello'));
console.log([a, b][+true].find(o => o.title === 'world'));

Related

Returning only a property of an element passed in to a forEach loop in JavaScript

let bloodGroup = bloodCodeArray.forEach(bloodCode => (bloodCode.code.toUpperCase() === bloodType.toUpperCase()) ? bloodCode.code : bloodType);
I expect this to return only a property of 'bloodCode' element (code) in my call back function of an angular code, but this is returning the entire element even though I'm selecting it in the ternary operator. Please explain.
let bloodGroup = bloodCodeArray.map(bloodCode => (bloodCode.code.toUpperCase() === bloodType.toUpperCase()) ? bloodCode.code : bloodType);
As per your requirement, You have to use Array.map() method which returns a new array by applying the callback function on each element of an array.
Live Demo :
const bloodCodeArray = [{
code: 'A'
}, {
code: 'o'
}, {
code: 'b'
}, {
code: 'O+'
}];
const bloodType = 'O';
let bloodGroup = bloodCodeArray.map(bloodCode => (bloodCode.code.toUpperCase() === bloodType.toUpperCase()) ? bloodCode.code : bloodType);
console.log(bloodGroup);
let bloodGroup = bloodCodeArray
.filter(bc => (bc.code.toUpperCase() === bloodType.toUpperCase()) ? bc.code : bloodType)
.map(bg=>bg.code)
.pop()
I was able to resolve this by using this code does anyone has a shorter or prettier way of doing the same?
After going through the comments on the question I realized using forEach will not work as it only returns undefined.

Using Array.prototype.every or Array.property.some depending on condition

I'm trying to make a function to filter some data using OR/AND logical operator depending on what the user selects.
That means I need to use Array.prototype.every (AND) or Array.property,some (OR) to fullfill my requirement.
To avoid code redundancy I was trying to do something like this:
const functionApplied = condition === 'ALL'
? myArray.every
: myArray.some;
functionApplied(item => {
... aux code ...
})
functionApplied.call(item => {
... aux code ...
})
Is there an analogous way to do it like this?
I know I could do something like this, but I'm just curious about above sintax...
const auxFunction = (item) => {...};
if (condition === 'ALL') {
myArray.every(item => auxFunction(item));
} else {
myArray.some(item => auxFunction(item));
}
You can definitely do something similar to what you're hoping to achieve. Here's one way:
function checkCondition(condition, booleanFunc, myArray) {
const functionApplied = condition === 'ALL'
? myArray.every.bind(myArray)
: myArray.some.bind(myArray);
return functionApplied(booleanFunc);
}
console.log(checkCondition('ANY', (item) => {return item > 2}, [1,4,5,6]));
console.log(checkCondition('ANY', (item) => {return item > 2}, [4,5,6]));
console.log(checkCondition('ANY', (item) => {return item > 2}, [1,2]));
console.log(checkCondition('ALL', (item) => {return item > 2}, [1,4,5,6]));
console.log(checkCondition('ALL', (item) => {return item > 2}, [4,5,6]));
VLAZ comment is another good direction.
Yep, VLAZ comment is the way I wanted, this works:
const functionApplied = condition === 'ALL'
? Array.prototype.every
: Array.prototype.some;
functionApplied.call(myArray, item => {
... aux code
Thanks everyone for your quick answers :)
I would personally use the following:
const fn = condition === 'ALL' ? "every" : "some";
const result = myArray[fn]((item) => {
// ... aux code ...
});
Storing the function name every or some in a variable called fn. Then calling it supplying your aux code.
You can use a variable holding the property name, and then use dynamic property access.
function functionApplied(condition) {
return functionApplied === 'ALL' ? 'every' : 'some';
}
let result = myArray[functionApplied(condition)](item => { ... });
const result = (myArray[condition === 'ALL' ? 'every': 'some'])(item => auxFunction(item))
this is minimal one line answer you can find
feel free to to seprate condition and min looping function

javascript - simplify: if Var is empty-ish then "", else enclose Var with text

I am writing es templates.
I want to make the codes as simple as possible and at best avoid using (function(){return XXX})()
The context: When a list has nothing, prints nothing, otherwise prints the list with ul tags around.
${
// same filter 2 times
arr.filter( d=>d.prop1=="a" ).length==0
? ""
: `<ul> ${ arr.filter( d=>d.prop1=="a" ).map(d=>`<li>${d.text}</li>`) } </ul>`
}
or
${
// function makes it bulky
(function(){
let arr2 = arr.filter( d=>d.prop1=="a" );
if( arr2.length == 0 ){
return ""
}else{
return `<ul> ${ arr2.map(d=>`<li>${d.text}</li>`) } </ul>`
}
})()
}
one more context, sometimes the problem is like this:
const NAMES = [
{ name:"John" },
{ name:"Michael", nickname:"Mike" },
];
NAMES.map( n=>`name: ${n.name} ${ n.nickname? "("+n.nickname+")":"" }` ).join("\n")
// can simplify n.nickname? "("+n.nickname+")":"" ?
Anyone come up with a way to simplify these? Thanks.
Using array.some is a bit faster than checking the length of the filtered array.
${
ARR.some(o => !!o.attr)
? `<ul>${ARR.filter(o => !!o.attr).map(o => (`<li>${o.attr}</li>`))}</ul>`
: ""
}
Also, since most templates don't print false value, you can simplify with &&.
${ ARR.some(o => !!o.attr) && `<ul>${ARR.filter(o => !!o.attr).map(o => (`<li>${o.attr}</li>`))}</ul>` }
If you do not want to maintain the duplicated condition, using a variable is necessary, so I don't know any other way rather than using a function. Using the tricks from above, you can reduce the function size a bit.
${
((arr) => {
arr = arr.filter(o => !!o.attr);
return !!arr.length && `<ul>${arr.map(o => (`<li>${o.attr}</li>`))}</ul>`;
})(ARR)
}
For NAMES, you can just use backsticks.
NAMES.map(o => (`Name: ${o.name}${o.nickname ? ` (${o.nickname})` : ""}`))
You can assign filter value to object and then apply length in condition part of ?:. Then you can use that object in true part to get map.
Your code will look like below.
(a = arr.filter(d => d.prop1 == "a")).length ? `<ul> ${ a.map(d=>`<li>${d.prop1}</li>`) } </ul>` : "";
Try it below.
function getTemplate(arr) {
return (a = arr.filter(d => d.prop1 == "a")).length ? `<ul> ${ a.map(d=>`<li>${d.prop1}</li>`) } </ul>` : "";
}
console.log(getTemplate([{prop1: 'a'}])); // output : <ul> <li>a</li> </ul>
console.log(getTemplate([{prop1: 'b'}])); // output :
Similarly with NAMES
Use (n.nickname || "") which will return "" in case of value is null or undefined.
At last replace () with '' so if there is no nickname then it would have () at end and we can remove it with replace.
const NAMES = [{
name: "John"
},
{
name: "Michael",
nickname: "Mike"
},
];
// Use (n.nickname || "") which will return "" in case of value is null or undefined.
// At last replace () with empty string so if there is no nickname then it would have () at end and we can remove it with replace.
let result = NAMES.map(n => `name: ${n.name} ${"(" + (n.nickname || "") + ")" }`.replace(' ()', '')).join("\n");
console.log(result);

How can I filter the result of a ternary that's inside a map?

I'm 100000% new to the ternary world, so I really don't understand what's going on. I have the following:
categories.forEach((category) => {
const errorCategory = {
[category]: response.map(
(r) => r.ds_category === category && r.ds_name
),
};
errors = { ...errors, ...errorCategory };
});
I want to filter the r.ds_name to remove all "false" results, how could I do this? I tried:
Doing the filter straight away (r.ds_name.filter(blablabla)) but I get a "this is not a function" error.
Switching from ternary to the old school function, and didn't get any results either.
Filtering errorCategory (errorCategory = errorCategory.filter((item) => item === "false"), but I also got the "this is not a function" error.
Thanks :(
To filter an array, I'd recommend using '.filter' instead of '.map'. This will remove the elements which do not match the requirement set. Assuming response is an object which is an array, or other object which implements 'filter', you can do the following (note the extra brackets):
categories.forEach( ( category ) => {
const errorCategory = {
[ category ]: response.filter(
(r) => (r.ds_category === category && r.ds_name)
),
};
//Do stuff
}
You can use ternary operator in a filter method like this
const newArray = array.filter( element => {
element.property === "text" ? true : false
})
It check for element.property is equal to "text". If it is equal it returns true. If not returns false. But you dont need to do that. You can simply do this
const newArray = array.filter( element => {
element.property === "text"
})
This would return the same result

Using if-else statement in a block []

I have the following statement:
arr.push([student.name,student.id]);
I want to add an if-else block in this statement so I could add student.name only if the if is true, something like:
arr.push([student.name if (validName(student.name))
,student.id]);
But this syntax is not valid. Is there a proper way to achieve this idea?
EDIT:
My array contains a lot of elements and I want to add to most of them (if not all of them) some kind of check. Something like:
arr.push([student.name if (validName(student.name)),
student.id if (validId(student.id) && idContainsNine(student.id)),
student.avg if (student.avg !== 'undefined'),
...
]);
I push the values only if the if statement is true. If it false, it will not push it. for example if validName(student.name) returns false it will not push student.name in the array.
You could take a conditional operator and get only an array with valid values.
array.push(validName(student.name)
? [student.name, student.id]
: [student.id]
);
An other approach is to use functions which return after a check either an array with the value or without.
For using this result, you need to spread the array and if it does not contain any element, it does not increase the length of the array.
cost
includeName = name => validName(name) ? [name] : [],
includeId = id => validId(id) && idContainsNine(id) ? [id] : [],
includeAVG = avg => avg !== 'undefined' ? [avg] : [];
arr.push([
...includeName(student.name),
...includeId(student.id),
...includeAVG(student.avg)
]);
Another solution could be to use an array of checks and return in case of unwanted items an own Symbol (if undefined or ``null` is a used value) and filter the array before pushing it to the result set.
const
EMPTY = new Symbol('empty'),
checkName = ({ name }) => validName(name) ? name : EMPTY,
checkId = ({ id }) => validId(id) && idContainsNine(id) ? id : EMPTY,
checkAVG = ({ avg }) => avg !== 'undefined' ? avg : EMPTY;
array.push([checkName, checkId, checkAVG]
.map(fn => fn(student))
.filter(v => v !== EMPTY)
);
Consider ternary operator.
arr.push([validName(student.name) ? student.name : '', student.id]);
Replace empty string value '' with what you want when you get invalid student.name.
Use this one.It may help you.
arr.push([student.name,(student.id ? student.id : '')]);

Categories

Resources