I need to "translate" the following loop from JavaScript to Ruby:
for(i=0;i<=b.length-1;i++){
if(!(i%2)){
c+=b[i]
}
}
Here is how I tried to write the same in Ruby:
until i == b.length-1 do
unless i%2 == true
c += b[i]
i += 1
end
end
The modulus operator in Ruby, however, seems to return false all the time; which renders the whole condition meaningless.
What am I doing wrong?
You should have:
unless i%2 == 1
or, equivalently:
if i%2 == 0
The reason of unexpected behavior is that Ruby treats all values (including 0) except false and nil as "truthy" in conditional statements.
Both in JavaScript and Ruby the modulus operator is expected to return an integer not a boolean:
2 % 2
# => 0
3 % 2
# => 1
So, to check if i is even, you have to implement your condition like this:
unless i % 2 != 0
# ...
However, for the purpose I think it's better to use one of the methods Integer#even? and Integer#odd?:
if i.even?
#...
In Javascript, 0 and -0 are falsy values and therefore evaluate to false when doing comparisons. All other Numbers evaluate to true.
In Ruby, there is no implicit type conversion when comparing objects, and 0 evaluates to true. If you want to do your comparison in Ruby, you should use
if i%2 == 0
instead of your code.
Related
I was playing around with JSconsole and found something strange. The value of "0" is false
"0" == false
=> true
The value of false when used in ternary returns the second value
false ? 71 : 16
=> 16
However the value "0" which equals false when used in ternary returns the first value.
"0" ? 8 : 10
=> 8
However, if you use 0 as the value, it returns the second value
0 ? 4 : 5
=> 5
0 == "0"
=> true
I'm afraid this doesn't make sense to me.
Non-empty string is considered as truth value in conditional statements, conditional expressions and conditional constructs.
But when you compare a string with a number with ==, some conversion will take place.
When comparing a number and a string, the string is converted to a
number value. JavaScript attempts to convert the string numeric
literal to a Number type value. First, a mathematical value is derived
from the string numeric literal. Next, this value is rounded to
nearest Number type value.
And == don't have the Transitive Property of Equality:
you can't say if a == b, b == c, then a == c.
An example will be:
"0" == false // true
false == "\n" //true
and guess the result of "0" == "\n"? Yes, the result is false.
"0" is a string of length>0 which is true. Try
0 ? 8 : 10
and see. It will return 10.
== does type conversion and hence when you do
"0" == false
it returns true. When you do
0 == "0" //true
It also returns true as again type conversion is taking place. Even though one is a number and the other one is a string it returns true. But if you use ===, no type conversion is done and 0 === "0" will return false.
A nice explanation of == & === is given here.
From the docs:
The equality operator(==) converts the operands if they are not of the same type, then applies strict comparison.
The identity operator(===) returns true if the operands are strictly equal with no type conversion.
I'm afraid this is an example of why you should use === - plain old == performs type conversion. Try
"0"===false
JavaScript leads to tons of WTFs.
Check out "Javascript WTF" on YouTube...
Essentially, you are requesting a conversion from string to boolean.
This is defined as "string is not empty".
Whereas you assumed that javascript does string -> int -> boolean if the string happens to contain a number.
It's sensible. But these automatic conversions lead to programming errors, which is why I prefer typesafe languages (with compile time type checking) for larger projects.
For fun, try these:
("0" * 1) ? 71 : 16
("0" + false) ? 71 : 16
So I'm doing a puzzle to evaluate Kaprekar's Routine and in the first section I need to check to make sure the 4 digit input has at least two unique digits so I did this:
let numArr = num.toString().split("");
if (numArr[0] == numArr[1] && numArr[2] && numArr[3]) {
return 0;
}
I tried searching but I keep finding links to short-circuiting operators. I was expecting to write out numArr[0] == into every && block but to my surprise it worked. Can anyone explain why this returns 0 for 3333 but does not for 1234? I assumed numArr[2] and numArr[3] would just evaluate to true automatically.
There is a thing called operator precedence. The operator with higher precedence happens first. == happens before &&. When you have more than one operator of the same precedence it goes by 'associativity' which is generally left to right (= for example is right to left); so let's take another look at your code
if ( ((numArr[0] == numArr[1]) && numArr[2]) && numArr[3] )
Let's take just the first piece. Doing 3 == 3 is true and since none of the operators are 0, the if statement is true. But with 1234, 1 == 2 is false, so the expression short circuits to false. Generally when something (like an if statement) accepts a boolean value && a non zero/undefined/false value, the expression is considered true (I may be wrong). If you do the below you should get true
if ( numArr[0] && numArr[1] && numArr[2] && numArr[3] )
To answer your other question, generally when people work with a set of data in JS they use lodash. You can find the if there is 2 unique values easily with the line blow. uniq(array, func) returns an array with unique values in the same order. See the documentation
_.uniq("3333".toString().split(""), v=>v).length >= 2 //false
_.uniq("1224".toString().split(""), v=>v).length >= 2 //true
It is because
For String 3333
num[0] is 3,num[1]=3,num[2]=3,num[3]=3
Expressions evaluate based on precedence of operators
and when the operators have the same precedence they get executed from left to right
In this case == has highest precedence over &&
so,
num[0]==num[1] ,it is 3==3 true
then
true && num[2] && num[3] => true&&3&&3 => true
For string 1234
num[0]=1,num[1]=2,num[2]=3,num[3]=4
num[0]==num[1] ,1==2 is false
so now the expression is
false && num[2] && num[3]
For && operator if the first operand is false,it ignore the rest of the expression
so now it just results as false
Hope this helps
You have three expressions being evaluated
// loose-equality, so true if after type-coersion, the values are equivalent
// this is the only condition that is actually changing in your code, unless
// you have a number with less than 4 digits
numArr[0] == numArr[1]
// is a non-empty string so it's 'truthy'
numArr[2]
// is a non-empty string so it's 'truthy'
numArr[3]
Anything that is not Falsy (false, 0, "", null, undefined, and NaN) is Truthy
Therefore, you need to write additional code to check for unique digits.
I'm playing around in javascript and I am wondering if you could make all
values greater than -1 evaluate to true and all values from -1 and down evaluate to false?
Right now 1 == true and everything else equals false if you write it like this:
var i = 0;
if (i) {...} // I want this to be true
i = 1;
if (i) {...} // This is the only thing that is true
EDIT: With evaluate I mean that I don't runt a comparison, e.g. 0 > -1.
I want JavaScript to coerce the number into a boolean value.
you mean this?
if ( i > -1 ) {
....
}
No, you can't change that, because it's built into the way the JavaScript == operator coerces values between types.
If you have a loose equality expression (==) where one of the operands is a boolean (true or false) and the other is a number, the JavaScript engine will try to convert the boolean into a number and will compare the result. true converts to 1 if you try to convert it to a number, and so that's why 1 == true.
Just wondering if anyone has come across this before.
I found in a project (that was handed over from another developer) a conditional statement that looked something like this:
if (variableOne == true | variable2 == true) {
// Do something here
}
It didn't error, so seems to work. But, myself and a colleague have never seen an OR statement with a single pipe |, only 2 ||.
Can anyone shed light on this mystery?
Thanks,
James
This is a bitwise OR operator. It will first convert it into a 32 bit integer, then apply the bitwise OR operation to the two numbers that result. In this instance, since Boolean(1) is true and Number(true) is 1, it will work fine without issue (the == operator will always return a boolean, and a if statement converts anything to a boolean). Here are a few examples of how it works:
1 | 0; // 1
0 | 0; // 0
0 | 1; // 1
1 | 1; // 1
true | false; // 1
false | false; // 0
2 | 1; // 3 (00000010, 00000001) -> (00000011)
As both sides have to be converted to a number (and therefore evaluated), this may cause unexpected results when using numbers when the logical OR statement (||) was meant to be used. For this, take these examples:
var a = 1;
a | (a = 0);
console.log(a); // 0
var b = 1;
b || (b = 0);
console.log(b); // 1
// I wanted the first one
var c = 3 | 4; // oops, 7!
Reference: http://www.ecma-international.org/ecma-262/5.1/#sec-11.10
That's a bitwise OR, see the documentation from Mozilla: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators)
The two pipes syntax "||" means it short circuits the logical expression. Evaluating only the needed until it knows the result.
What does it means?
if(a==null || a.type=='ok')
If a is null, it will evaluate only the first part of the expression, without errors on javascript side.
if(a==null | a.type=='ok')
If a is null in this case, you will have an error, since it will evaluate the second part of the expression too.
It's the same thing on others C type languages: Java, C,C++
And the same thing applies to '&' and '&&'
| is a bitwise OR, which in some very limited cases can substitute the ||.
An important difference is that with | both operands are evaluated, unlike with the || which evaluates the second operand only if the first is false.
Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators
I'm looking at some Javascript code that is:
if ( a>2 | b>4 ) { ... }
(ignore the ... above). What's the | doing? I assume it's logical OR, but all the references I could find online speak about ||, and I can't find anything mentioning just |. Thanks in advance
It's the bitwise or. || is logical or.
The bitwise or (|) coerces the values to 32 bit integers and returns the 32 bit integer with each bit set to 1 if either of the two bits in the corresponding locations is 1 and 0 if they are both 0.
Logical or (||) evaluates to the first value if it's not falsey, otherwise it evaluates to the second value.
You almost definitely want || instead of |.
The difference between || and | is already explained in the other answers.
However, in the above code, | has the same effect as || due to type conversion.
true and false are mapped to 1 and 0 and we have
0 | 0 = 0
1 | 0 = 1
0 | 1 = 1
1 | 1 = 1
The same goes into the other direction, 1 evaluates to true and 0 to false.
So in this example,
if ( a>2 | b>4 )
will have the same result as
if ( a>2 || b>4 )
Note: This really only works with the two values 0 and 1.
This could be some kind of micro-optimization.
Update:
However, a short test reveals that using the bitwise OR for this purpose is way slower (at least in Chrome 9):
http://jsperf.com/js-or-test
Conclusion: Don't use it instead of logical OR :) Mostly likely someone forgot the second | and is just lucky that the code produces the same result.
Use boolean operators for boolean operations and bitwise operators for fancy bit masking. This might be worth reading: MDC - Bitwise Operators.
Single | is a bitwise-OR while double (||) is a logical-OR.
Bitwise-OR takes the binary representation of the two source values and ORs them together so that if either of the values has a bit set, the resulting value's bit will also be set (repeat for all the bits in the two source values).
Logical-OR concerns itself with true and false values (where 0 maps to false and non-zero maps to true - that's simplified, JavaScript has more specific rules). If either source value is true then the result is true.
Looks like second pipe just got lost, otherwise it is a smelly hack. See what really happens:
if ( Boolean( Number(a>2) | Number(b>4) ) ) { ... }
(Number is special here because bitwise operators are working with 32-bit integers)
It works because Number(true) === 1 && Number(false) === 0.