How to check two conditions with && correctly - javascript

I want to loop through an array and check if each element is a number OR a string that could potentially turned into a number (e.g. "42"). If it can be "converted" then the element should be stored in a new array.
This is my code where I push all converted elements into a new array. Notice: I also want to count how many elements were "converted" from a string into a number and how many were not.
function numberConverter(arr) {
var converted = []
var counterConverted = 0
var counterNotConverted = 0
for (var c of arr) {
if (typeof c == "string" && Number(c) == "number") {
counterConverted++;
parseInt(c, 10);
converted.push(c)
} else {
counterNotConverted++
}
}
if (counterConverted == 0) {
return "no need for conversion"
} else {
return counterConverted + " were converted to numbers: " + converted + "; " + counterNotConverted + " couldn't be converted"
}
}
I know that my if condition
if(typeof c == "string" && Number(c) == "number")
is flawed logically, but I can't make up why.
Thanks for any hints and please explain it in beginner terms.

You can test if a string could be converted to a number like so:
val !== "" && Number.isNaN(Number(val)) === false
And the code could be written like so:
function numberConverter(arr) {
var converted = [];
var notconverted = [];
arr.forEach(function(val) {
if (typeof val === "number") {
converted.push(val);
} else if (typeof val === "string" && val !== "" && Number.isNaN(Number(val)) === false) {
converted.push(Number(val));
} else {
notconverted.push(val);
}
});
console.log("converted", converted);
console.log("not converted", notconverted);
}
numberConverter([0, "1", "", "123-foo", undefined, null, true, [], {}]);

The best solution is to use a functional approach to the code rather than an imperative one.
let arrayNumbers = ["Vadim", 99, {}, [], "100", "55AA", "AA55", Infinity, "false", true, null, -65.535, 2E1, "2E2"].filter( value => value !== null && value != Infinity && value !== '' && !isNaN(Number(value)) && !['boolean','array','object'].includes(typeof value)).map(value => +value);
console.log('Was Converted to Numbers:', arrayNumbers);

You need to check typeof string and isNaN in ESLint way (Number.isNaN(Number())).
function numberConverter(arr) {
const converted = [];
let counterConverted = 0;
for (let i = 0; i < arr.length; i += 1) {
const str = arr[i];
if (str && typeof str === 'string' && !Number.isNaN(Number(str))) {
const number = parseInt(str, 10);
converted.push(number);
counterConverted += 1;
}
}
const counterNotConverted = arr.length - converted.length;
if (counterConverted === 0) {
return 'No need for conversion.';
}
return `${counterConverted} were converted to numbers: ${converted.join(',')}; ${counterNotConverted} couldn't be converted`;
}
console.log(`'${numberConverter(['id', null, {}])}'`); // No need for conversion.
console.log(`'${numberConverter(['1', '-1', 'val'])}'`); // 2 were converted to numbers: [1,-1]; 1 couldn't be converted
console.log(`'${numberConverter(['1', '-1', '0', '1.5', 'val'])}'`); // 4 were converted to numbers: [1,-1,0,1]; 1 couldn't be converted

Related

I failed Javascript tech interview but I dont know why

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.

Why is my code returning the else statement and undefined and not the totalBasketballScore?

I really thought I had this code correct. I am trying to calculate basketball score with free throws, 2 pointers and 3 pointers. The output when I console.log the totalBasketballScore ends up being 'All entries must be numbers' and undefined. What do I need to change so I get the score when I put the 3 values in the parameters?
function totalBasketballScore(numberFreeThrows, numberMidRange, numberThreePointers) {
const freeThrows = 1;
const midRange = 2;
const threePointers = 3;
if (typeof numberFreeThrows === 'number' && numberMidRange === 'number' && numberThreePointers === 'number') {
let totalFreeThrows = freeThrows * numberFreeThrows;
let totalMidRange = midRange * numberMidRange;
let totalThreePointers = threePointers * numberThreePointers;
let gameTotal = totalFreeThrows + totalMidRange + totalThreePointers;
return gameTotal;
} else {
console.log('All Entries Must Be a Number');
}
}
console.log(totalBasketballScore(1, 2, 4));
Another approach that can be used is isNaN(). isNaN can be used to check if the value is Not a Number. If isNaN() returns false, the value is a number.
function totalBasketballScore(numberFreeThrows, numberMidRange, numberThreePointers) {
const freeThrows = 1;
const midRange = 2;
const threePointers = 3;
if(isNaN(numberFreeThrows)=== false && isNaN(numberMidRange)=== false && isNaN(numberThreePointers)=== false) {
let totalFreeThrows = freeThrows * numberFreeThrows;
let totalMidRange = midRange * numberMidRange;
let totalThreePointers = threePointers * numberThreePointers;
let gameTotal = totalFreeThrows + totalMidRange + totalThreePointers;
return gameTotal;
} else {
console.log('All Entries Must Be a Number');
}
}
console.log(totalBasketballScore(1, 2, 4));
You should use typeof per each parameter, like this:
if(typeof numberFreeThrows === 'number' && typeof numberMidRange === 'number' && typeof numberThreePointers === 'number'){
} else {
}

is there a way to check if a string is of this *x.xx.xxxx* format in JavaScript?

I want a function to check if a string is of format x.xx.xxxx in javascript. For example, s.xf.ssfs should return true. And sx.xf.hsdf should return false. Also s.fsd.sfdf should return false.
Here's a reducer version
const isValid = s => s.split('.').reduce((b,a,i) => a.length === [1,2,4][i] ? b+1 : b, 0) === 3
console.log(isValid('s.xf.ssfs'));
console.log(isValid('ds.xf.ssfs'));
console.log(isValid('5.32.9850'))
For a non-regex, for loop option:
const test1 = 's.xf.ssfs';
const test2 = 'sx.xf.hsdf';
function correctFormat(str) {
if (str.length !== 9) {
return false;
}
if (str[1] !== '.' || str[4] !== '.') {
return false;
}
for (let i = 0; i < 9; i++) {
if (i !== 1 && i !== 4 && str[i] === '.') {
return false;
}
}
return true;
}
console.log(correctFormat(test1));
console.log(correctFormat(test2));
You can try using regex:
const regex = new RegExp('[a-z][.][a-z]{2}[.][a-z]{4}');
console.log(regex.test('s.xf.ssfs'));
console.log(regex.test('s.fsd.sfdf'));
As an alternative you can also split the string by periods and check the length of each individual item:
function check(s){
let a = s.split('.');
return a.length == 3 && a[0].length == 1 && a[1].length == 2 && a[2].length == 4;
}
console.log(check('s.xf.ssfs'));
console.log(check('sx.xf.hsdf'));
Regular Expressions are what you are looking for here. Simply define a regex and use the test() method to evaluate a string. For example:
const regex = /^[a-z][.][a-z]{2}[.][a-z]{4}$/
console.log(regex.test('s.xf.ssfs'))
console.log(regex.test('sx.xf.hsdf'))
If you require to accept letters and numbers you could use this regular expression instead to test against:
const regex = /^.[.].{2}[.].{4}$/
console.log(regex.test('s.5f.s9fs'))
console.log(regex.test('sx.xf.hsdf'))
From a brute force approach you could split the string by . into an array and check the length of the array, and each element within the array as follows:
let myArray = myString.split(".");
if(myArray.length !== 3){
return false
}
else if(myArray[0] !== 1 || myArray[1] !== 2 || myArray[3] != 4){
return false
}
else{return true}
Using regular expression you can achieve it.
1) This example work for letters from "a" to "z"
const format = /^[a-z]\.[a-z]{2}\.[a-z]{4}$/; //x.xx.xxxx
let test1 = format.test('s.xf.ssfs');
let test2 = format.test('sx.xf.hsdf');
console.log("test1: " + test1);
console.log("test2: " + test2);
2) This example work for letters from "a" to "z" and "A" to "Z"
const format = /^[a-zA-Z]\.[a-zA-Z]{2}\.[a-zA-Z]{4}$/; //X.Xx.xXXx
let test1 = format.test('S.Xf.sSFs');
let test2 = format.test('sx.XF.Hsdf');
console.log("test1: " + test1);
console.log("test2: " + test2);

how to fix: Array index is out of range

i have this problem
Have the function WildcardCharacters(str) read str which will contain two strings separated by a space. The first string will consist of the following sets of characters: +, , and {N} which is optional. The plus (+) character represents a single alphabetic character, the asterisk () represents a sequence of the same character of length 3 unless it is followed by {N} which represents how many characters should appear in the sequence where N will be at least 1. Your goal is to determine if the second string exactly matches the pattern of the first string in the input.
i have the solution with js, but now i am trying to solve with swift, i need your help.
this work with js, and i'm using swift v4.2
code with js
function WildcardCharacters(str) {
// code goes here
let strArr= str.split(' ')
let specChar = strArr[0]
let charStr = strArr[1].split('')
let arr = specChar.split('')
let letters = /^[A-Za-z]+$/
let i = 0
while(i< arr.length){
if(arr[i] == '+'){
if(!charStr[0].match(letters)) return "false"
charStr = charStr.slice(1,charStr.length)
}
else if(arr[i] == '*'){
let curr = charStr[0]
let j = 1, k = 0
if(arr[i+1] != undefined && arr[i+1] == '{'){
k = arr[i+2]
i = i+4
}else{
k = 3
i++
}
while(j < k){
charStr = charStr.slice(1,charStr.length)
if(charStr[0] != curr) return "false"
j++
}
charStr = charStr.slice(1,charStr.length)
continue
}
i++
}
if(charStr.length != 0) return 'false'
return "true"
}
// keep this function call here
WildcardCharacters("+++++* abcdemmmmmm");
code by Smakar20 (user github)
code with swift
extension String {
func isAlphanumeric() -> Bool {
return self.rangeOfCharacter(from: CharacterSet.alphanumerics.inverted) == nil && self != ""
}
func isAlphanumeric(ignoreDiacritics: Bool = false) -> Bool {
if ignoreDiacritics {
return self.range(of: "[^a-zA-Z0-9]", options: .regularExpression) == nil && self != ""
}
else {
return self.isAlphanumeric()
}
}
}
func wild (str: String) -> String
{
let strArr = str.split(separator: " ")
let specChar = strArr[0]
var charStr = Array(strArr[1])
let arr = Array(specChar)
var i = 0
while (i<arr.count)
{
if arr[i] == "+"
{
if !String(charStr[0]).isAlphanumeric()
{
return "false"
}
charStr = Array(charStr[0...charStr.count])
}
else if arr[i] == "*"
{
let curr = charStr[0]
var j = 0
var k = 0
if String(arr[i+1]).isAlphanumeric() != true && arr[i+1] == "{"
{
k = Int(String(arr[i+2]))!
i = i+4
}
else
{
k = 3
i += 1
}
while (j<k)
{
charStr = Array(charStr[1...charStr.count])
if charStr[0] != curr
{
return "false"
}
j += 1
}
charStr = Array(charStr[1...charStr.count])
continue
}
i += 1
}
if charStr.count != 0
{
return "false"
}
return "true"
}
wild(str: "+++++* abcdemmmmmm")
if str is "++*{5} gheeeee" then the second string in this case does match the pattern, so your program should return the string true. If the second string does not match the pattern your program should return the string false.
heeelp

Simple calculator example using array to store input values

The input values are stored in an array, the below loop is to calculate the final result, by looping through the array and appending the operators and numbers to a variable which is then evaluated.
privateCalculate = function () {
var total;
for(i = 0; i < init.sequence.length; i++) {
if(init.sequence[i] === "+" || init.sequence[i] === "-" ||
init.sequence[i] === "*" || init.sequence[i] === "/" ||
init.sequence[i] === "(" || init.sequence[i] === ")")
{
total += init.sequence[i];
} else {
init.sequence[i] = parseFloat(init.sequence[i]);
total += init.sequence[i];
}
}
console.log(eval(total));
//console.log((parseFloat(1)+parseFloat(2))/parseFloat(2));
},
The function produces "NaN"
You said your input is: ["5","+","5"]
You don't need to parse it, because evaltakes as parameter a String
Just do this:
var inputArray = ["5","+","5"];
eval(inputArray.join('')) // -> 10

Categories