I have a simple question about JavaScript algorithm
https://www.codewars.com/kata/56747fd5cb988479af000028/train/javascript
I'm solving this problem. The explanation of this problem is to extract two letters from the middle of the odd-numbered character
What I'm curious about is
function getMiddle(s) {
//Code goes here!
let answer = "";
if (s.length % 2 !== 0) {
answer += s[Math.floor(s.length / 2)];
} } else {
answer += s.slice(
(Math.floor(s.length / 2 - 1), Math.floor(s.length / 2 + 1))
);
}
return answer;
}
console.log(getMiddle("test"));
console.log(
"test".slice(
Math.floor("test".length / 2 - 1),
Math.floor("test".length / 2 + 1)
)
);
Is the return value from the getMiddle function different from the console.log('test'.slice~') in the end?
The difference is that one is the return value of the function and the other is just taken directly from the console, but I don't know why it's the same code, but the value is differentcrying
please help me
The problem is that in the function you have wrapped the pair of indices in parentheses:
answer += s.slice(
(Math.floor(s.length / 2 - 1), Math.floor(s.length / 2 + 1))
// ^ ^
);
Those parentheses will trigger an evaluation of what is between them, and that means the comma is then interpreted as a comma-operator. The result of that operation is then a single number that is passed as argument to s.slice. So you are actually calling slice with just one argument instead of two, and due to the comma operator, it is the second index that is used by slice. It is equivalent to s.slice(3)
In the second console.log you don't have those extra parentheses, and so there it works as it is intended.
NB: I assume the extra closing brace just before else is a typo.
Related
In the example below, I don't want to make a counter as a param. Rather, I just want to return '+ 1' each time so that what gets returned is the number of steps it takes. My issue lies with the base case. If I do return + 1, I get the correct number of steps plus one additional step so I tried just return but that delivers NaN. Is it even possible?
var numberOfSteps = function(num) {
if (num == 0) {
return;
} else {
if (num % 2 == 0) {
return 1 + numberOfSteps(num/2);
} else {
return 1 + numberOfSteps(num - 1);
}
}
};
edit : The goal is to track how many steps it takes to reduce a number to 0. If it's even, divide by 2 or else subtract by 1. Ultimately, I want to return the number of steps it takes for any given number to get reduced to 0 following those rules
I hope the point has gotten through in the long comment thread and other answers that return + 1 is equivalent to return (+1), that is, return the integer positive one. And since there are no steps to take once you've reached zero, +1 is the wrong answer. Similarly, a plain return is functionally equivalent to return undefined. But undefined is not a number, and you're going to run into problems if you later try to add 1 to it. So the solution from the comments or other answers to return the correct number of steps, which in this case 0, will fix your code.
I would like to point out another way to solve this, though:
const numberOfSteps = (n) =>
n <= 0
? 0
: 1 + numberOfSteps (n % 2 == 0 ? n / 2 : n - 1)
console .log (numberOfSteps (12))
There are superficial differences here from the other solutions, such as using an arrow function, using a conditional statement (ternary) rather than if-statements, and using <= 0 instead of < 0 to avoid possible infinite loops on negative numbers.
But the fundamental difference is that this code only has one recursive branch. I think this is a better match to the problem.
We can think of this as a function which answers "How many steps does it take to reach 0 from our input number if each step cuts even numbers in half and subtracts one from odd ones?" Well that logically leads to a base case (we're already at 0) so have to return 0, and a recursive one (we're at some positive integer) so have to add 1 to the total steps required from our next entry.
By doing this single recursive call and adding one to the result, we make it clearer what the recursion is doing.
If this is unclear, then this alternative might show what I mean:
const takeStep = (n) =>
n % 2 == 0 ? n / 2 : n - 1
const numberOfSteps = (n) =>
n <= 0
? 0
: 1 + numberOfSteps (takeStep (n))
Think you just need to return 0 when it's...zero.
var numberOfSteps = function(num) {
if (num == 0) {
return 0;
} else {
if (num % 2 == 0) {
return 1 + numberOfSteps(num/2);
} else {
return 1 + numberOfSteps(num - 1);
}
}
}
return + 1 maybe doesn't do what you think it does: it returns the number 1. + here means positive not negative, there is no addition or subtraction going on. It will also give you one too many steps.
return; by itself returns undefined, which when converted to a Number, translates to NaN, because, well, it's not a number.
Ultimately I want to take this:
2x + 3 = 5
and solve for x, by first subtract 3 from both sides so 2x = 2, then divide both sides by 2 so x = 1. I was thinking a lot how one should go about making a function like this in JavaScript that can return an array of the steps done in order, including the result. Obviously "eval" wouldn't do anything for this, so seemingly one has to re-create equations.
I initially thought to first of all, ignore X, and just try to make a function that can solve simple equations, without eval or any built-in function.
I figured that the first step is to break up the terms using .split, but I was having some trouble with this, as I need to split for multiple symbols. For example, say I have the simple expression to evaluate: 3 - 6 * 3 / 9 + 5. So before we even get into order of operations, just splitting up each term (and categorizing them) is the hard part, which is the main concrete-question I have at this point.
I started simply splitting one after the other, but I was having some problems, and especially considering the order.
function solve(eq) {
var minuses = eq.split("-"),
pluses = minuses.map(x=> x.split("+")),
timeses = pluses.map(x=>x.map(y=>y.split("*"))),
dividers = timeses.map(x=>x.map(y=>y.map(z=>z.split("/"))));
console.log(minuses, pluses, timeses, dividers);
}
solve("3 - 6 * 3 / 9 + 5");
As you can see, for each successive operator I need to map through each of he elements of the previous one to split it, and then I am left with an array of arrays etc...
So 1) how can I split up these terms more efficiently, without making a new variable for each one, and manually recursively mapping through each one? Seemingly I should just have some kind of dictionary of array keeping track of orders of operations (not considering parenthesis or exponents now): ["*","/","+","-"] -- and given that array, generate something similar to the last array in the above example ("dividers") which contains only constants, and somehow keep track of the which elements each of the stored arrays follows...
and 2) How can I solve the expression given the arrays of values?
I was just a little confused with the logic, I guess I need to work up from the last array and solve the constants one at a time, keeping track of which operator is the current one, but I'm not sure how exactly.
While your problem doesn't require to construct, binary expression tree is a good way to brainstorm the logic to solve a math query.
So for the query 3 - 6 * 3 / 9 + 5, the representative binary expression tree is:
plus
|_minus
| |_3
| |_divide
| |_times
| | |_3
| | |_6
| |_9
|_5
to solve above tree, you recursively solve from the leaf level up to the root.
Again, you don't need to construct a tree. It just helps us to see the logic of parsing here:
Get the last minus or plus expression in query and solve left and right child of that expression.
If no plus/minus, get the last times/division expression and solve left and right child
If meet a number, return that number value.
Given above logic, here is an implementation:
function solve(str) {
var expressionIndex = Math.max(str.lastIndexOf("-"), str.lastIndexOf("+"));
if (expressionIndex === -1) {
expressionIndex = Math.max(str.lastIndexOf("*"), str.lastIndexOf("/"));
}
if (expressionIndex === -1) {
var num = Number.parseInt(str.trim());
if (isNaN(num)) {
throw Exception("not a valid number");
} else {
return num;
}
} else {
var leftVal = solve(str.substring(0, expressionIndex).trim());
var rightVal = solve(str.substring(expressionIndex + 1).trim());
switch (str[expressionIndex]) {
case "+":
return leftVal + rightVal;
case "-":
return leftVal - rightVal;
case "*":
return leftVal * rightVal;
case "/":
return leftVal / rightVal;
}
}
}
function parse(str) {
var expressionIndex = Math.max(str.lastIndexOf("-"), str.lastIndexOf("+"));
if (expressionIndex === -1) {
expressionIndex = Math.max(str.lastIndexOf("*"), str.lastIndexOf("/"));
}
if (expressionIndex === -1) {
var num = Number.parseInt(str.trim());
if (isNaN(num)) {
throw Exception("not a valid number");
} else {
return { type: "number", value: num };
}
} else {
var leftNode = parse(str.substring(0, expressionIndex).trim());
var rightNode = parse(str.substring(expressionIndex + 1).trim());
return {
type: "expression",
value: str[expressionIndex],
left: leftNode,
right: rightNode
};
}
}
console.log(solve("3 - 6 * 3 / 9 + 5"));
console.log(parse("3 - 6 * 3 / 9 + 5"));
Above is a solution for very simple query with only +, -, *, / (no parenthesis, e.g.). For solving a equation like your first example requires a lot more of work.
EDIT: add a parse function to return the tree.
You can do that in following steps:
First of all use split() and split by the + and - which will occur after multiplication and division.
Then use map() on array and split() it again by * and /.
Now we have a function which will which will evaluate an array of numbers with operators to single number.
Pass the nested array to complete multiplication and division.
Then pass that result again to sovleSingle and perform addition and subtraction.
The function works same as eval as long as there are no brackets ().
Note: This doesnot matters the which occurs first among + and - or which occurs first among * and /. But *,/ should occur before +,-
function solveSingle(arr){
arr = arr.slice();
while(arr.length-1){
if(arr[1] === '*') arr[0] = arr[0] * arr[2]
if(arr[1] === '-') arr[0] = arr[0] - arr[2]
if(arr[1] === '+') arr[0] = +arr[0] + (+arr[2])
if(arr[1] === '/') arr[0] = arr[0] / arr[2]
arr.splice(1,1);
arr.splice(1,1);
}
return arr[0];
}
function solve(eq) {
let res = eq.split(/(\+|-)/g).map(x => x.trim().split(/(\*|\/)/g).map(a => a.trim()));
res = res.map(x => solveSingle(x)); //evaluating nested * and / operations.
return solveSingle(res) //at last evaluating + and -
}
console.log(solve("3 - 6 * 3 / 9 + 5")); //6
console.log(eval("3 - 6 * 3 / 9 + 5")) //6
I eventually want to get the hang of dynamic programming but before that, I am having a hard time understanding the flow of this. I understand recursion but I'm having trouble understanding the flow of this:
function fib(n) {
if (n == 0) return 0;
if (n == 1) return 1;
return fib(n - 1) + fib(n - 2);
}
console.log(fib(3));
if I have a small integer of 3, it does not pass those 2 conditionals so it hits return fib(n-1)+fib(n-2); So to my understanding, that will go through the first part of that first: fib(n-1) (3-1 = 2)... 2 does not satisfy either of those conditionals so it runs fib(n-1) (2-1 = 1). 1 DOES satisfy one of the conditionals so it returns 1 and breaks that part of it.
Now to to the next part: fib(n-2) . (3-2 = 1). 1 does satisfy one of the conditionals so it returns 1 .
So in the end, isn't that returning 1 + 1 ?
I'm not sure where I'm going wrong in my understanding.
You are correct in that fib(3) should return 2, because 2 is the 3rd number in the Fibonacci sequence (starting at 0)
It helps to write out it out as tree:
fib(3)
/ \
fib(2) fib(1)
/ \ \
fib(1) fib(0) 1
/ \
1 0
above you can see how each recursive call goes all the way to 0 or 1 before returning a result back up the previous layer.
One of my favorite ways to do this is to start with the base cases and go backwards:
fib(0); // => 0
fib(1); // => 1
Then we get to the default case:
fib(2); // == fib(1) + fib(0) == 1 + 0 ==> 1
fib(3); // == fib(2) + fib(1) == 1 + 1 ==> 2
fib(4); // == fib(3) + fib(2) == 2 + 1 ==> 3
This is much easier than trying to figure out fib(4) first since you need to nest. Looking at the function it's easy to see what to try.
Also know that calls to the same function doesn't get any special treatment. It runs until it returns with a value and it's arguments and local variables are local to the call so every fib call has its own n and it waits for the two calls to return to sum the results.
I am trying to build a calculator in javascript but I am stuck and don't know how to proceed. every time someone click on 1 + 1 / 2, for exemple I am creating an array that pushes everything that was typed so in the case above the array would be
[1, "+", 1, "/", 2];
However, I can't figure it out how to transform this array into an actual mathematical value.
I had an idea of looping through all elements
like this:
for(var i=0; i<arrayCharacters.length ;i++){
if(arrayCharacters[i] != "*" || arrayCharacters[i] != "/" || arrayCharacters[i] != "+" || arrayCharacters[i] != "*"){
arrayNumbers.push(arrayCharacters.slice(0, i));
console.log(arrayNumbers);
}
}
It's very incomplete because I got stuck. Can anyone help me?
var result=eval(arrayCharacters.join(""));
You could also parse the expression manually, however this requires building up a tree, as math isnt evaluated left to right.
If you really want to parse it on your own (which is far better then eval), you could use a math notation that really goes from left to right , so its much easier to parse ( As #Scott suggested). An implementation:
var stack=[];
var arrayCharacters=[1,2,"/",1,"+"];
for(var i=0;i<arrayCharacters.length;i++){
var char=arrayCharacters[i];
if(typeof char==="number"){
stack.push(char);
continue;
}
var op2=stack.pop()||0;
var op1=stack.pop()||0;
var res;
if(char=="+"){
res=op1+op2;
}
if(char=="-"){
res=op1-op2;
}
if(char=="*"){
res=op1*op2;
}
if(char=="/"){
res=op1/op2;
}
stack.push(res);
}
var result=stack.pop();
Math Syntax (RPN (1)):
1+2 => 1 2 +
1/2+3 => 1 2 / 3 +
1+2/3 => 1 2 3 / +
(1+2)/3 => 1 2 + 3 /
1/2/3+4/5/6 => 1 2 / 3 / 4 5 / 6 / +
http://jsbin.com/zofeqitiba/edit?console
"eval" function is a very good choice in your case. Also you can use the math.js library, which comes with a powerful expression parser.
http://mathjs.org
I'm working with JavaScript, and I have two strings like this :
var week1="1.345.7", // each digit refers to one day of the week
week2="123..6.";
Now I want to return a value from 1 to 7 which refers to the number of days in common.
In the previous example I should return 2, because we have both weeks have Monday and Wednesday (1 and 3).
How can I achieve the above ?
Each character is either . or its index, so you can represent it with a bit.
"0b" + "1.345.7".replace(/./g, c=>c==='.'?0:1); // "0b1011101"
"0b" + "123..6.".replace(/./g, c=>c==='.'?0:1); // "0b1110010"
Then, you can use the bitwise operator AND &:
"0b1011101"
& "0b1110010";
// 0b1010000
Finally, you only need to convert it back to string and count the number of 1:
0b1010000.toString(2).split('1').length-1; // 2
Probably I wouldn't do it like this, but just for fun :)
In fact, to waste less memory, you could store the data as numbers instead of strings
0b1011101; // 93 - only needs 64 bits!
0b1110010; // 114 - only needs 64 bits!
And to retrieve the data
0b1011101 >> 6 & 1; // 1 - 1st bit
0b1011101 >> 5 & 1; // 0 - 2nd bit
0b1011101 >> 4 & 1; // 1 - 3rd bit
0b1011101 >> 3 & 1; // 1 - 4th bit
0b1011101 >> 2 & 1; // 1 - 5th bit
0b1011101 >> 1 & 1; // 0 - 6th bit
0b1011101 >> 0 & 1; // 1 - 7th bit
Get a list of digits from the first string using a quick regexp, then filter it to keep only the ones that are in the other one, then see how many there are with length.
(week1.match(/\d/g) || []) . filter(n => week2.includes(n)) . length
In a "code golf" spirit, you could write this as a generator, taking advantage of the ability of for...of to loop across characters in a string:
function *common(a, b) {
for (c of a) if (c !== '.' && b.includes(c)) yield c;
}
console.log(...common(a, b))
Just to throw another option out there, if you split a string with an empty string argument, you get an array of one-character strings. This makes them easy to iterate, but also if you're targeting browsers that support ECMAscript 5.1 (most notably IE 9+) you can use the reduce function. It's generally a good fit when you're passing in an array that you want to iterate and return a single value. This could be more concise, but I think it's easier to follow this way.
var week1="1.345.7";
var week2="123..6.";
function weekDaysInCommon(w1, w2) {
//split to convert w1 to an array.
//"1.345.7" becomes ["1", ".", "3", "4", "5", ".", "7"]
w1 = w1.split('');
//countCharactersAtSameIndex(w2) returns the function to use as the callback, with w2 accessible to it via closure
//the second arg, 0, is the initial value.
return w1.reduce(countCharactersAtSameIndex(w2), 0);
}
function countCharactersAtSameIndex(comparisonWeek) {
comparisonWeek = comparisonWeek.split('');
return function(total, day, index) {
if(comparisonWeek[index] === day) {
return total + 1;
} else {
return total;
}
}
}
document.write(weekDaysInCommon(week1, week2) + ' days in common');
Further reading:
MDN has a good doc on the reduce function - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce