What is the correct way to test this condition when 'members' and 'departments' may not exist? Is there a way to check for their existence while testing the value without causing an error?
if (state.staff.members.length < 5 || state.staff.departments.length < 5) {}
The cleanest (and in my opinion, best) way to do this is with a try...catch block. That way, you can safely and gracefully fail if the properties you are looking for don't exist, like so:
var state;
function myFunction() {
try {
if (state.staff.members.length < 5 || state.staff.departments.length < 5) {
return "PASS";
}
} catch (e) {
console.log(e.toString());
return "PASS"
}
return "FAIL";
}
console.log(myFunction());
Lots and lots of falsy checks
if (
(
state &&
state.staff &&
state.staff.members &&
state.staff.members.length < 5
) ||
(
state &&
state.staff &&
state.staff.departments &&
state.staff.departments.length < 5
)
) {
console.log("foo");
}
I would suggest taking the lodash approach with _.get() instead to encapsulate the checks.
if (
_.get(state, "staff.members.length") < 5 ||
_.get(state, "staff.departments.length") < 5
){
console.log("foo");
}
Try this :)
if (
(state.staff.members && state.staff.members.length < 5) ||
(state.staff.departments && state.staff.departments.length < 5)
) {
// do something
}
if ((state.staff.members && state.staff.members.length < 5) || (state.staff.departments && state.staff.departments.length < 5)) {}
This assumes that you only want the condition to pass when at least one of the properties is set.
Edit: In response to your comment I would then write it the following way
if ((state.staff.members && state.staff.members.length < 5)
|| (state.staff.departments && state.staff.departments.length < 5)
|| state.staff.hasOwnProperty('members') === false
|| state.staff.hasOwnProperty('departments') === false
) {}
For those scenarios, I like to use a little helper like this:
/**
* Accesses nested properties and returns a default value if it encounters null or undefined along the way.
* #param fallback A fallback value if any property or its value is null or undefined.
* #param path The path to access a nested property
*/
export const propOrDefault = <T, R>(fallback: R) => (...path: string[]) => (obj: T | null | undefined): R =>
path.reduce((partialObj, propertyName) => {
if (partialObj && propertyName && partialObj.hasOwnProperty(propertyName)) {
return partialObj[propertyName] || fallback;
}
return fallback;
}, obj);
This is TypeScript, but it should get the point across. And the additional type info might help with understanding.
Example usage:
const isValid = propOrDefault(0)('staff', 'members', 'length')(state) < 5;
As you can see, this helper uses currying so you could pre-configure it for later use like so:
const propOrTen = propOrDefault(0);
const countStaffMembers = propOrTen('staff', 'members', 'length');
const result = countStaffMembers(state);
There are loads of libraries out there with similar tools like lodash and ramda.
Related
I was only allowed to use google document for writing.
Could you please tell me what I did wrong? The recruiter wont get back to me when I asked her why I failed
Task 1:
Implement function verify(text) which verifies whether parentheses within text are
correctly nested. You need to consider three kinds: (), [], <> and only these kinds.
My Answer:
const verify = (text) => {
const parenthesesStack = [];
for( let i = 0; i<text.length; i++ ) {
const closingParentheses = parenthesesStack[parenthesesStack.length - 1]
if(text[i] === “(” || text[i] === “[” || text[i] === “<” ) {
parenthesisStack.push(text[i]);
} else if ((closingParentheses === “(” && text[i] === “)”) || (closingParentheses === “[” && text[i] === “]”) || (closingParentheses === “<” && text[i] === “>”) ) {
parenthesisStack.pop();
}
};
return parenthesesStack.length ? 0 : 1;
}
Task 2:
Simplify the implementation below as much as you can.
Even better if you can also improve performance as part of the simplification!
FYI: This code is over 35 lines and over 300 tokens, but it can be written in
5 lines and in less than 60 tokens.
Function on the next page.
// ‘a’ and ‘b’ are single character strings
function func2(s, a, b) {
var match_empty=/^$/ ;
if (s.match(match_empty)) {
return -1;
}
var i=s.length-1;
var aIndex=-1;
var bIndex=-1;
while ((aIndex==-1) && (bIndex==-1) && (i>=0)) {
if (s.substring(i, i+1) == a)
aIndex=i;
if (s.substring(i, i+1) == b)
bIndex=i;
i--;
}
if (aIndex != -1) {
if (bIndex == -1)
return aIndex;
return Math.max(aIndex, bIndex);
} else {
if (bIndex != -1)
return bIndex;
return -1;
}
};
My Answer:
const funcSimplified = (s,a,b) => {
if(s.match(/^$/)) {
return -1;
} else {
return Math.max(s.indexOf(a),s.indexOf(b))
}
}
For starters, I'd be clear about exactly what the recruiter asked. Bold and bullet point it and be explicit.
Secondly, I would have failed you from your first 'for' statement.
See my notes:
// Bonus - add jsdoc description, example, expected variables for added intention.
const verify = (text) => {
// verify what? be specific.
const parenthesesStack = [];
for( let i = 0; i<text.length; i++ ) {
// this could have been a map method or reduce method depending on what you were getting out of it. Rarely is a for loop like this used now unless you need to break out of it for performance reasons.
const closingParentheses = parenthesesStack[parenthesesStack.length - 1]
// parenthesesStack.length - 1 === -1.
// parenthesesStack[-1] = undefined
if(text[i] === “(” || text[i] === “[” || text[i] === “<” ) {
parenthesisStack.push(text[i]);
// “ will break. Use "
// would have been more performant and maintainable to create a variable like this:
// const textOutput = text[i]
// if (textOutput === "(" || textOutput === "[" || textOutput === "<") {
parenthesisStack.push(textOutput)
} else if ((closingParentheses === “(” && text[i] === “)”) || (closingParentheses === “[” && text[i] === “]”) || (closingParentheses === “<” && text[i] === “>”) ) {
parenthesisStack.pop();
// There is nothing in parenthesisStack to pop
}
};
return parenthesesStack.length ? 0 : 1;
// Will always be 0.
}
Not exactly what the intention of your function or logic is doing, but It would fail based on what I can see.
Test it in a browser or use typescript playground. You can write javascript in there too.
Hard to tell without the recruiter feedback. But i can tell that you missundertood the second function.
func2("mystrs", 's', 'm') // returns 5
funcSimplified("mystrs", 's', 'm') // returns 3
You are returning Math.max(s.indexOf(a),s.indexOf(b)) instead of Math.max(s.lastIndexOf(a), s.lastIndexOf(b))
The original code start at i=len(str) - 1 and decrease up to 0. They are reading the string backward.
A possible implementation could have been
const lastOccurenceOf = (s,a,b) => {
// Check for falsyness (undefined, null, or empty string)
if (!s) return -1;
// ensure -1 value if search term is empty
const lastIndexOfA = a ? s.lastIndexOf(a) : -1
const lastIndexOfB = b ? s.lastIndexOf(b) : -1
return Math.max(lastIndexOfA, lastIndexOfB)
}
or a more concise example, which is arguably worse (because less readable)
const lastOccurenceOf = (s,a,b) => {
const safeStr = s || '';
return Math.max(safeStr.lastIndexOf(a || undefined), safeStr.lastIndexOf(b || undefined))
}
I'm using a || undefined to force a to be undefined if it is an empty string, because:
"canal".lastIndexOf("") = 5
"canal".lastIndexOf(undefined) = -1
original function would have returned -1 if case of an empty a or b
Also, have you ask if you were allowed to use ES6+ syntax ? You've been given a vanilla JS and you implemented the equivalent using ES6+. Some recruiters have vicious POV.
For example, I have flag1, flag2, flag3,..., flagN as boolean values for flags.
I need to write an if statement like this: If flagK is false, then turn off the "K" part of the condition:
if (condition0 && (flag1 && condition1) && (flag2 && condition2) ... && (flagN && conditionN))
{
// do something
}
// For example, if flag 2 is false then the condition should only be:
if (condition0 && (flag1 && condition1) && ... && (flagN && conditionN))
{
//do something}
}
Particularly, given an example like this (for demo only not my real problem):
const divby2 = false; //if this is false, then ignore the **i%2 === 0** below
const divby3 = true;
const divby4 = true;
const divby5 = true;
//......const divbyN....
const array = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,42,45,241,526]
array.forEach((i) => {
if(i >= 0 && (divby2 && i%2 === 0) && (divby3 && i%3 === 0)) {
console.log(i) // output here should be 3,6,9,12 instead of nothing
}
}
)
Example Result:
The term you are looking for is "short-circuit" similar to the way in real electronic circuit if some part is not working you just short circuit it and by pass flow to rest
if(i >= 0 && ( divby2 && i%2 === 0 || !divby2) && (divby3 && i%3 === 0))
In this case if you are wanting that filtered number should be divisible by 2 that time you set divby2 = true
And when you just want to ignore and don't care about the divisibility by 2 you set divby2 = false
In pseudo
(is-checking-for-divby-2? AND is-current-number-divby-2?) OR (NOT is-checking-for-divby-2?)
As soon as you are not checking for divby 2 you make this logic fragment true so it won't affect evaulation of the follolwing logic fragments
And..Why should you bother making this fragments TRUE?
Because you ANDing them
Similarly you can go for divby3, divby4 ...
I would have an object with your conditions, and then filter out the functions you don't want to run, and then just reduce the object to a single function which runs all of the enabled functions:
const conditions = {
divby2: i => i % 2 === 0,
divby3: i => i % 3 === 0,
};
const enabled = {
divby2: false, //if this is false, then need to ignore the **i%2 === 0** below
divby3: true
}
const enabledConditions = (i) => {
return Object.entries(conditions).filter(
([key, value]) => enabled[key]
).reduce((carry, [_, condition]) => {
return condition(i) && carry
}, i !== false);
}
//......const divbyN....
const array = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,42,45,241,526]
array.forEach((i) => {
if(i >= 0 && enabledConditions(i)){
console.log(i) //output here should be 3,6,9,12 instead of nothing
}
}
)
I have a simple sort:
dataCopy.sort((a: Data, b: Data) => {
if (a[label] === null || b[label] === null) return 0;
if (direction === "desc")
return a[label] > b[label] ? 1 : -1;
return 0;
});
The "Data" type is:
export type Data = {
[key: string]: string | number | null;
};
I check if a[label] and b[label] are both null and I still get the error "Object is possibly 'null'.ts(2531)". It seems to only happen with the > and < operators.
It's probably just not smart enough to see that you checked. BTW you didn't post where label was coming from, but assuming that's not the problem, try this:
dataCopy.sort((a: Data, b: Data) => {
const aLabel = a[label];
const bLabel = b[label];
if (aLabel === null || bLabel === null) return 0;
if (direction === "desc")
return aLabel > bLabel ? 1 : -1;
return 0;
});
Sometimes you have to factor things out so that TypeScript can see that you've checked for conditions like === null.
I'm trying to create a filter with javascript with 4 input fields so I'm guessin 16 combinations of possible searches. I can search all 4 at once or 1 input at a time but for some reason when I add other statements I get wierd results. Is there a better way to implement a filter?
var unfilteredFloorplans = floorplanJSON.floorplanData;
filteredFloorplans = [];
for (var i = 0; i < unfilteredFloorplans.length; i++) {
if (unfilteredFloorplans[i].city == req.body.cityName &&
unfilteredFloorplans[i].building == req.body.buildingName &&
unfilteredFloorplans[i].bedrooms == req.body.minBedroom &&
unfilteredFloorplans[i].baths == req.body.maxBathroom) {
console.log(unfilteredFloorplans[i].city);
filteredFloorplans.push(unfilteredFloorplans[i]);
}
}
So now I need to write 15 more if statements? Rather than copy them in I'd like to ask if this is correct and does anyone know how you could implement this with a switch statement?
Edit: And when I say 15 more statements I mean one for if they just pick city, andother if they pick city and bedrooms etc. It just seems inefficient
A minimal fix would be to combine your "and" with "or", but note how this turns the code into a hard-to-read mess:
var unfilteredFloorplans = floorplanJSON.floorplanData;
filteredFloorplans = [];
for (var i = 0; i < unfilteredFloorplans.length; i++) {
if ((req.body.cityName == '' || unfilteredFloorplans[i].city == req.body.cityName) &&
(req.body.buildingName == '' || unfilteredFloorplans[i].building == req.body.buildingName) &&
(req.body.minBedroom == '' || unfilteredFloorplans[i].bedrooms == req.body.minBedroom) &&
(req.body.maxBathroom == '' || unfilteredFloorplans[i].baths == req.body.maxBathroom)) {
console.log(unfilteredFloorplans[i].city);
filteredFloorplans.push(unfilteredFloorplans[i]);
}
}
(BTW, this looks like a good exercise for combining conjunctions with disjunctions.)
Edit I'd recommend to put the filtering into a separate function, and to introduce an additional helper function. Also, use a more consistent naming and use "===" instead of "==".
function filterByEquality(formValue, dataValue) {
if (formValue === '') return true;
if (formValue === dataValue) return true;
return false;
}
function filterFloorplan(form, data) {
if (!filterByEquality(form.city, data.city)) return false;
if (!filterByEquality(form.building, data.building)) return false;
if (!filterByEquality(form.minBedrooms, data.bedrooms)) return false;
if (!filterByEquality(form.maxBathrooms, data.bathrooms)) return false;
return true;
}
var unfilteredFloorplans = floorplanJSON.floorplanData;
filteredFloorplans = [];
for (var i = 0; i < unfilteredFloorplans.length; i++) {
if (filterFloorplan(req.body, unfilteredFloorplans[i]);
console.log(unfilteredFloorplans[i].city);
filteredFloorplans.push(unfilteredFloorplans[i]);
}
}
You can reduce this code even further by learning about the Array.filter method. And you should fix the bug where for some fields should use ">=" or ">=" instead of "===". But I'll leave those things as an exercise.
Here's a simplified example of what your code may look like (in this example, I hardcoded the values representing the input choices):
var unfilteredFloorplans = [{
city: 'NY',
building: 'A',
bedrooms: 2,
baths: 1,
}];
var filteredFloorplans = unfilteredFloorplans.filter(
function(el) {
return el.city === 'NY' && el.building === 'A' && el.bedrooms >= 1 && el.baths >= 1;
}
);
console.log(filteredFloorplans);
The anonymous function being called inside the filter can be replaced with a named function like so:
function filterFloorplans(floorplan) {
return floorplan.city === 'NY' && floorplan.building === 'A' && floorplan.bedrooms >= 1 && floorplan.baths >= 1;
}
var filteredFloorplans = unfilteredFloorplans.filter(filterFloorplans);
You'll likely want to use this route since you can have any combination of the 4 input choices. As such, you'll want the filterFloorplans function to be "built-up" from other, smaller checks:
function testCity(userInputCity, floorplanCity) {
return userInputCity ? userInputCity === floorplanCity : true;
}
function filterFloorplans(floorplan) {
return testCity('NY', floorplan.city) && floorplan.building === 'A' && floorplan.bedrooms >= 1 && floorplan.baths >= 1;
}
This should be enough to get you started; feel free to comment if you get stuck
within a loop I have this
if(id < arr.length - 1 && a != null){
//lots of thing here
}
Can I store the operator id < arr.length - 1 into a variable? I don't want to have redundant code using else for above statement.
can I do like this ?
var check = a == true ? id < arr.length - 1 : false;
You are trying to store the condition (not operator).
// (within a loop)
var first_condition = id < arr.length - 1; // stored as true or false (boolean)
var second_condition = a !== null; // note the !== NOT !=
if ( first_condition && second_condition ) {
// lots of thing here
}
Although if you meant redundant as in else ifs with same condition, you can do nested if instead.
if ( first_condition ) {
if ( second_condition ) {
}
}
You can do this:
var condition_check=(id < arr.length - 1) && a !== null;
if (condition_ckeck){
//lots of things will happen
}