Compare multiple variables with a value in a single expression - ruby

I have two variables a and b. I want to compare both a and b to a value, say 10.
I can do it like this:
10 == a && 10 == b
But, I was wondering if there is any way to write it in a single expression? (E.g. like a == b == 10)

[a,b,3].all? {|x| x==10}
but in this case
[].all? {|x| x==10}
will also return true

Updated, after comment from aztaroth:
[a,b].uniq == [10]

Related

Expressing "equals" in pseudocode

I was just wondering if there is a special way of saying when something equals something. For example in python, if you declare something equals 2, you say something = 2, whereas when you check if something equals something else, you would say:
if something == somethingelse:
So my question is in pseudocode for algorithms if I'm checking to see if a entered password equals a stored password in an IF THEN ELSE ENDIF loop, would I use one or two equal signs:
WHILE attempts < 3
Get EnteredPassword
**IF EnteredPassword = StoredPassword THEN**
Validated = TRUE
ELSE
attempts = attempts + 1
ENDIF
ENDWHILE
Usually, pseudocode is very broad and every author has their own way of expressing it. As
Aziz has noted, usually x <- 1 is used for an assignment and x := x + 1 for an update. Read ':=' as 'becomes' instead of 'equals', however, they are interchangeably used. As for your question, both = and == are accepted answers, as long as it is clear to your reader what your intention is.
To express equals you use the equal mark symbol once, unlike in python where you use the symbol twice to compare two values (eg if variable == 'one'). An example syntax is:
variable = 'one'
WHILE variable = 'one' DO
SEND "hi" TO DISPLAY

How can I use conditional assignment in ruby

I want to set the value of a equal to the index found unless that index is zero, in which case I want to set it to some number minus that value. I am wondering if it is possible to perform this action (taken from python) in Ruby:
a='/-123456789X'.find(y)or 99-x
Does anyone know of a good way to do this?
Try this one. Given x and y
a = "/-123456789X".index(y) || 99 - x
In python string.find(other) will return the index of other or -1 if other does not exist in string.
In ruby string.index(other) will return the index of other or nil if other does not exist in string.
"Truthy" and "Falsey" values:
ruby acknowledges nil as "falsey" and 0 as "truthy"; but
python acknowledges 0 as "falsey" and -1 as "truthy"
So your current python code has 3 possible return values:
-1 (non-existent sub-string)
99 - x (existent sub-string starting with '/')
n (index of existent sub-string that does not start with '/')
In order to achieve an equivalent result in ruby your code could look like this:
str = '/-123456789X'
a = if y.start_with?('/') && str.index(y)
99 - x
else
str.index(y) || -1
end
Other alternatives include:
# Ruby >= 2.5 using `String#match?
str.match?(/\A#{y}/) ? 99 - x : str.index(y) || -1
That being said your actual request "I want to set the value of a equal to the index found unless that index is zero, in which case I want to set it to some number minus that value" seems a little different and I am not sure if this means that x is "that value" and what x should represent in that case.
Should x be the begining index?
Should x be the ending index?

Algorithm to rank numeric passcode?

I'm studying a (mobile) app where I need to get a user PIN:
a numeric "passcode" of 6/8 ciphers, input with something like this UI:
So, in a registration step, the user configure his one passcode (as it would be a password).
Let say the passcode must have a fixed size (say 8 ciphers: ********)
My question is related to a possible algorithm to verify/check the number that user choose, giving a bad rank in case of repeated ciphers or standard cipher patterns (12345678, 00001111), easily predicible by a malicious crackers...
Any idea for such an algorithm ?
At firs glance the algorithm could discourage (bad rank) a passcod containing repeated ciphers, simething like:
00117788
88886611
or "usual" ascending/descending patterns as:
12345678
98765432
Or numeric patterns related to personal, by example in my case, I'm born in 02 September 1963, so it could be a bad idea to have as passcode:
02091963
Instead, sequence that appear to me as "good" could be by example these one:
18745098
90574808
07629301
Collateral question: do you think that a numeric passcode of let say 8 ciphers could be an acceptable solution as "password" to validate a payment transaction ?
BTW, I'm coding in Ruby.
thanks for your patience!
giorgio
For your first 2 cases:
Number of repeated consecutive characters in the string:
str = "00117788"
str.chars.each_cons(2).select {|a,b| a == b}.count
#=> 4
Or as #CarySwoveland pointed out this will have the same result
str.size - str.squeeze.size
#=> 4
Number of incremented characters
str = "12345678"
str.chars.map(&:to_i).each_slice(2).select {|a,b| (a + 1) == b || (a - 1) == b }.count
#=> 4
#note this will also return 4 for "12563478"
# you could also use str.chars.map(&:to_i).each_cons(2).select {|a,b| (a + 1) == b || (a - 1) == b }.count
# This will return 7 for "12345678" and still return 4 for "12563478"
You could combine the above 2 as well like
str = "00117788"
str.chars.map(&:to_i).each_cons(2).select {|a,b| (a + 1) == b || (a - 1) == b || a == b }.count
#=> 6
As for the "personal" issue if you have the birth day then something as simple as this should work:
require 'date'
birth_day = Date.new(1963,9,2)
str = "02091963"
str == birth_day.strftime("%d%m%Y")
#=> true
Although for the last one I would suggest comparing multiple formats e.g. %Y%m%d and %m%d%Y etc. you could even do something like
str.chars.sort == birth_day.strftime("%d%m%Y").chars.sort
#=> true
To make sure they don't just use those numbers in some jumbled format.
Hopefully this would get you started since I don't know what your thresholds are for "good" and "bad" these are just suggestions for checking the values. Although it seems the definition for "good" should just be not "bad". Sort of like a validity check.
If I were to suggest a score of < 4 using methods 1 and 2 (or the combination method) && not an assortment of birth_day numbers would probably be sufficient e.g.
def tester(str,birth_date)
return false if ![6,8].include?(str.size)
b_day = birth_date.strftime("%Y%m%d").chars.sort
str.chars.map(&:to_i).each_cons(2).select do |a,b|
(a + 1) == b ||
(a - 1) == b ||
a == b
end.count < 4 && b_day != str.chars.sort
end
tester("00112233",Date.new(1963,9,2))
#=> false
tester("18745098",Date.new(1963,9,2))
#=> true
Seems like it works with your examples
arry = ["00117788","88886611","12345678","98765432","02091963","18745098","90574808","07629301"]
Hash[arry.map{|v| [v,tester(v,Date.new(1963,9,2))]}]
#=>=> {"00117788"=>false, "88886611"=>false,
"12345678"=>false, "98765432"=>false,
"02091963"=>false, "18745098"=>true,
"90574808"=>true, "07629301"=>true}

How do i find if element is not in a ruby array?

Ok so i have this array
array
=> [1620, 3093]
and I have a integer
num
=> 1620
is there an easy way to see if there is another number in the array that is not num
so for example
is there another number in the array that doesnt match num. So for the above example i would return true but if array was [1620, 1620] then i would return false
arr.any?{|x| x != num }
The above should work fine, is readable and efficient too!
array.reject{ |a| a == num }.size > 0
array.select{|array_num| array_num != num}.length > 0
EDIT: or even cleaner:
(array - [num]).empty?
Join the sorted array with a separator and find if there is a match with 2 adjacent numbers.
array.sort.join(",").include?("#{num},#{num}")

Using a block to find values matching criteria

To me this makes perfect sense:
triple = dice.collect {|value| if (dice.count(value) >= 3)} ---> Syntax error
OR
triple = dice.collect {|value| dice.count(value) >= 3} ----> Array of true/false
I want the value of the number, not the true or falsity of dice.count(). I know there must be a simple way of doing this.
It sounds like you want Array#select, not Array#collect (also known as Array#map).
collect/map will take each value and put the results of your block into an array. This is why you're seeing an array of true/false.
select will take each value, and return it as a member of an array if the block evaluates to true:
triple = dice.select{ |value| dice.count(value) >= 3 }
Your block needs to return whatever it is you want in the final array.
triple = dice.collect {|value|
if dice.count(value) >= 3
dice.count(value)
end
}
Note that this will return nil for elements < 3 (though you can add an else to return 0 or something). If you only want elements that match your query, you'll need to use dice.select()
As for your first code snippet,
triple = dice.collect {|value| THE_CODE_BLOCK_STARTS_HERE }
Thus, if (dice.count(value) >= 3) is an incomplete if statement. That's why you get syntax error.

Resources