Ruby Equal to vs Comparison; - ruby

I need help for understanding - What is the difference between Equal to and Comparison?
Here is the case
x == y means `Equal to`
x = 10 and y = 10
puts "X and Y are equal" if x == y
puts "X and Y are equal" if x <=> y
I know when and where can I use equal to, but when and where can I use Comparison <=>
Thanks

When you want to compare? It returns -1, 0, 1. For example, sorting users by first name:
users_by_first = users.sort { |u1, u2| u1.fname <=> u2.fname }
Here's another SO question asking about the spaceship operator.

<=> General comparison operator. Returns -1, 0, or +1, depending on whether its receiver is less than, equal to, or greater than its argument.
http://ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html
This is useful for sorting, for one thing.

Equality operators: == and !=
The == operator, also known as equality or double equal, will return true if both objects are equal and false if they are not.
"koan" == "koan" # Output: => true
The != operator, AKA inequality or bang-tilde, is the opposite of ==. It will return true if both objects are not equal and false if they are equal.
"koan" != "discursive thought" # Output: => true
Note that two arrays with the same elements in a different order are not equal, uppercase and lowercase versions of the same letter are not equal and so on.
When comparing numbers of different types (e.g., integer and float), if their numeric value is the same, == will return true.
2 == 2.0 # Output: => true
Comparison operators
Objects such as numbers and strings, which can be compared (amongst themselves) in terms of being greater or smaller than others, provide the <=> method, also known as the spaceship method. When comparing two objects, <=> returns -1 if the first object is lesser than the second (a < b), 0 in case they are equal (a == b) and 1 when the first object is greater than the second (a > b).
5 <=> 8 # Output: => -1
5 <=> 5 # Output: => 0
8 <=> 5 # Output: => 1
Most comparable or sortable object classes, such as Integer, Float, Time and String, include a mixin called Comparable, which provides the following comparison operators: < (less than), <= (less than or equal), == (equal), > (greater than), >= (greater than or equal). These methods use the spaceship operator under the hood.
Comparison operators can be used in objects of all the above classes, as in the following examples.
# String
"a" < "b" # Output: => true
"a" > "b" # Output: => false
# Symbol
:a < :b # Output: => true
:a > :b # Output: => false
# Fixnum (subclass of Integer)
1 < 2 # Output: => true
2 >= 2 # Output: => true
# Float
1.0 < 2.0 # Output: => true
2.0 >= 2.0 # Output: => true
# Time
Time.local(2016, 5, 28) < Time.local(2016, 5, 29) # Output: => true
When comparing numbers of different classes, comparison operators will implicitly perform simple type conversions.
# Fixnum vs. Float
2 < 3.0 # Output: => true
2.0 > 3 # Output: => false
More info about Ruby operators is available at this blog post.

Related

Create a method to find if a number is a power of 2?

I have this code to return true if num is a power of 2.
def is_power_of_two?(num)
result = num.inject(0) {|n1, n2| n2 ** n1}
if result == num
true
else
false
end
end
p is_power_of_two?(16)
I keep getting an error though. How could I fix and simplify this code?
Clearly, n is a non-negative integer.
Code
def po2?(n)
n.to_s(2).count('1') == 1
end
Examples
po2? 0 #=> false
po2? 1 #=> true
po2? 32 #=> true
po2? 33 #=> false
Explanation
Fixnum#to_s provides the string representation of an integer (the receiver) for a given base. The method's argument, which defaults to 10, is the base. For example:
16.to_s #=> "16"
16.to_s(8) #=> "20"
16.to_s(16) #=> "10"
15.to_s(16) #=> "f"
It's base 2 we're interested in. For powers of 2:
1.to_s(2) #=> "1"
2.to_s(2) #=> "10"
4.to_s(2) #=> "100"
8.to_s(2) #=> "1000"
16.to_s(2) #=> "10000"
For a few natural numbers that are are not powers of 2:
3.to_s(2) #=> "11"
5.to_s(2) #=> "101"
11.to_s(2) #=> "1011"
We therefore wish to match binary strings that contain one 1.
Another Way
R = /
\A # match beginning of string ("anchor")
10* # match 1 followed by zero or more zeroes
\z # match end of string ("anchor")
/x # free-spacing regex definition mode
def po2?(n)
(n.to_s(2) =~ R) ? true : false
end
po2?(4) #=> true
po2?(5) #=> false
And one for the road
This uses Fixnum#bit_length and Fixnum#[]:
def po2?(n)
m = n.bit_length-1
n[m] == 1 and m.times.all? { |i| n[i].zero? }
end
po2? 0 #=> false
po2? 1 #=> true
po2? 32 #=> true
po2? 33 #=> false
Try:
def is_power_of_two?(num)
num != 0 && (num & (num - 1)) == 0
end
It is well explained here (for C#, but #GregHewgill's explanation applies here as well)
I would do something like this, using Ruby's Math module.
def power_of_two?(n)
Math.log2(n) % 1 == 0
end
Or, if you wanted to be really cool:
def power_of_two?(n)
(Math.log2(n) % 1).zero?
end
Some IRB output:
2.1.0 :004 > power_of_two?(2)
=> true
2.1.0 :005 > power_of_two?(32768)
=> true
2.1.0 :006 > power_of_two?(65536)
=> true
This method assumes that the input is a positive integer.
Source
Another way to solve this is to go the other way around than most of the answers here - we can use the number 1 to start and find out if the number is the power of two. Like this:
def power_of_two?(num)
product = 1
while product < num
product *= 2
end
product == num
end
We start with 1. Then we multiply the 1 by 2, and keep multiplying by 2 until the product is larger than num (product < num). Once we hit that condition, we stop, exit the loop, and check if it's equal to num (product == num). If it is, the num is the power of 2.
As was pointed out in the comments above, you were getting errors because you're trying to use the inject method on a non-iterable (an int). Here's a solution using the suggested log2
def is_power_of_two?(num)
result = Math.log2(num)
result == Integer(result)
end
Note: will fail with very big numbers close to binaries (like 2 ^ 64 - 1). A foolproof version (but slower) would be:
def is_power_of_two?(num)
while (num % 2 == 0 and num != 0)
num /= 2
end
num == 1
end
Please comment any improvements that any of you may find.
Here is another solution that uses recursion:
def power_of_2?(number)
return true if number == 1
return false if number == 0 || number % 2 != 0
power_of_2?(number / 2)
end
In my opinion, the easiest -- but maybe a little long -- way of doing what you need to do is just writing this recursive method like so:
def power_of_two?(number)
continue = true
if number == 1
return true
end
if number % 2 != 0
return false
else
while continue == true do
if number.to_f / 2.0 == 2.0
continue = false
return true
else
if number % 2 != 0
continue = false
return false
else
number /= 2
continue = true
end
end
end
end
end
One is a power of two (2^0), so it first checks if the number given is 1. If not, it checks if it is odd, because 1 is the only odd number that is a power of two.
If it is odd it returns false and moves on to the else statement. It will check if the number divided by 2 is two, because then it would obviously be a power of 2. It does this as a float, because 5/2 in Ruby would return 2.
If that is false, it then again checks if the number is odd -- unnecessary on the first round, necessary after that. If the number is not odd, it will divide the number by two and then do the loop another time.
This will continue until the program resolves itself by getting 2 or any odd number, and returns true or false, respectively.
I ran into this one in a bootcamp application prep. I'm not a math person and don't understand a few of these methods, so I wanted to submit a common sense approach for people like me. this requires little knowledge of math, except to know a number to the second power will be the result of some number multiplied by itself.
def is_power_of_two?(num)
num.times {|n| return true if (n+1) * (n+1) == num}
false
end
this method counts up to the num variable starting at 1 and returns true if (any of those numbers in the sequence multiplied by itself) is equal to num & if num is not 0 (more on that below).
example:
num = 9
1 * 1 == 9 #=> false
2 * 2 == 9 #=> false
3 * 3 == 9 #=> true
true is returned and method is finished running.
the #times method requires an integer > 0, so this edge case is "handled" by virtue of the fact that #times does nothing with "0" as the variable and returns false when outside of the #times iteration.
def power_of_two?(num)
num.to_s(2).scan(/1/).length == 1
end

Why do we need spaceship operator? [duplicate]

This question already has answers here:
What is the Ruby <=> (spaceship) operator?
(6 answers)
Closed 7 years ago.
If we have <, >, and ==, the total order is determined by those. Why do we need <=>?
we Don't need <=>.
a<=>b
is equivalent to:
if a<b
return -1
elsif a>b
return 1
else
return 0
end
It is there for convenience and it was taken from perl.
<=> is the basis of Comparable, so you don't have to implement all of the compare functions yourself. It's easier and less error-prone to just implement one function instead of three.
The "spaceship" operator is for comparison, not equality. It's similar in concept to C's strcmp function.
From the String class:
string <=> other_string → -1, 0, +1 or nil
Comparison — Returns -1, 0, +1 or nil depending on whether string is less than, equal to, or greater than other_string.
In short, == returns a boolean expressing equality, while <=> returns a number expressing comparative value. If the first object is of greater value than the second, <=> returns +1. If it's of lesser value, -1 is returned. If the two have the same value, 0 is returned.
The "value" of an object can be defined to be just about anything. For String, however, <=> checks the lexicographic ordering of the two arguments.
Therefore:
"abc" == "abc" # true
("abc" <=> "abc") == 0 # true
You are correct that there is redundancy between <, ==, > and <=>. In fact, when <, ==, > are defined, <=> is automatically defined.
This operator is sometimes called a "signum" function. It provides the most concise way to customize sort order. For example:
require "ostruct"
# Fake "rows" with OpenStructs
my_data = [
OpenStruct.new({ :name => "Ben", :age => 50 }),
OpenStruct.new({ :name => "Abe", :age => 50 }),
OpenStruct.new({ :name => "Cab", :age => 51 })
]
# Sort by age descending, then name ascending
puts my_data.sort { |a, b| 2 * (b.age <=> a.age) + (a.name <=> b.name) }
This works because the value from <=> is always -1, 0, or 1. I don't know of a more efficient way to do general-purpose sorting.

Check if the sum of two different numbers in an array equal a variable number?

In Ruby, I would like to take an array of numbers, select 2 different numbers, add those 2 numbers together and see weather there equal to a variable x.y'd a variable x. Here is the code I used
def arrayIsEqual? (numArray, x)
return true if numArray.sample + numArray.sample == x
return false if numArray.empty? || numArray.count == 1
end
for example
numArray = [4,2,7,5]
x = 11
arrayIsEqual (numArray, n) should return true, since 4 + 7 = n(11)
How do I get this to work?
I don't want it to be 2 random numbers, just any 2 different numbers that add up to n
It looks like you're trying to see if there are any two numbers in the array that add up to the specified value x. However, your code just picks two numbers at random and checks if those numbers add up.
Ruby has the Array#combination method, which generates all combinations of a given length:
def contains_pair_for_sum?(arr, n)
!!arr.uniq.combination(2).detect { |a, b| a + b == n }
end
A few things to note:
First, we named it according to Ruby conventions: each word is separated_by_underscores. The ? on the end means that the method is a predicate method and returns a true or false value.
Inside the method, a few things happen. Let's look at that line, piece by piece.
arr: We take the array that was passed in.
<...>.uniq: We only look at the unique elements (because the OP wants to pick two different numbers).
<...>.combination(2): We ask for all combinations from the array of length 2. If the array was [4, 5, 6], we'd get [[4, 5], [4, 6], [5, 6]].
<...>.detect { |a, b| a + b == n }: We look for the first combination that adds up to n. If we found one, that's the result of that method. Otherwise, we get nil.
!!<...>: Finally, we take the result we got from detect and negate it twice. The first negation produces a Boolean value (true if the value we got was nil, or false if it's anything else); the second negation produces a Boolean value that's identical to the truth value of the first negation. This is a Ruby idiom to coerce a result into being either true or false.
Let's see it in action:
array = [4, 5, 9, 7, 8]
contains_pair_for_sum?(array, 11)
# => true (because [4, 7] sums to 11)
contains_pair_for_sum?(array, 17)
# => true (because [9, 8] sums to 17)
contains_pair_for_sum?(array, 100)
# => false (no pair matched)
I understand that your question is "is there any pair of numbers in my array equals x", in which case this will do what you need:
def has_pair_equal?(num_array, x)
(0..num_array.length-1).any? do |i|
num_array[i+1..-1].any? { |n| n + num_array[i] == x }
end
end
This checks all sums of pairs of numbers in the array, and checks if their sum is x. sample randomly picks an item from the array, which means that what your code does is "return true sometimes if there is a pair of numbers in my array equals x"
def array_is_equal? (num_array, x)
equality = 0
num_array.each do |a|
equality += 1 if a == x
return true if equality == 2
end
return false
end
Use lowercase and underscores for variables in Ruby. The convention is different here than in some other languages.
One liner
x=[4,2,7,5]; x.each_with_index.any? {|y,i| x.each_with_index.any? {|z,j| unless i==j; z+y==11; end } }
And as a function
def pair_sum_match?(arr, x)
arr.each_with_index.any? do |y,i|
arr.each_with_index.any? do |z,j|
unless i==j
z+y==x
end
end
end
end
Updated: Added each_with_index to avoid self inclusion on checks. It's a lot longer now :-/
Just iterate over it once and use the target number to see if it matches. 100 times faster then most of the answers here
numbers = ( -10..10 ).to_a
numbers.unshift( numbers.first + -1 ) # if you do -20 or 20
numbers.push( numbers.last + 1 )
target = 5
searched = { }
matches = { }
numbers.each do |number|
if searched[ target - number + 1 ] == true
matches[ "#{ number }_plus_#{ target - number }" ] = target
end
searched[ number + 1 ] = true
end
ap matches

What is the difference between '&&' and '&' in Ruby

Recently, I observed a very interesting result in Ruby while making use of && and & for the input combination of 0 & 1.
Can someone please explain the below output with respect to the above mentioned two operators? The below is implemented using Ruby 2.0.0-p451
2.0.0-p451 :006 > 0 && 1
=> 1
2.0.0-p451 :008 > 0 & 1
=> 0
Thank you
&& is the logical AND operator. It will be truthy, IFF both operands are truthy. And it is lazy (aka short-circuiting), which means it will stop evaluating as soon as the result has been fully determined. (So, since both operands need to be truthy, if the first operand is falsy, you already know that the result is going to be falsy, without even evaluating the second operand.) It will also not just return true or false, but rather return the operand which determines the outcome. IOW: if a is falsy, it'll return a, otherwise it'll return b:
nil && (loop {})
# => nil
# Note: the infinite loop is *not* evaluated
# Note: the return value is nil, not false
true && nil
# => nil
true && 'Hello'
# => 'Hello'
& simply calls the method &. It will do whatever the object wants it to do:
def (weirdo = Object.new).&(other)
puts 'Whoah, weird!'
'Hello, ' + other
end
weirdo & 'World'
# Whoah, weird!
# => 'Hello, World'
In general, & and its brother | are expected to perform conjunction and disjunction. So, for booleans, they are perform AND and OR (TrueClass#&, FalseClass#&, NilClass#&, TrueClass#|, FalseClass#|, NilClass#|) with the exception that & and | are standard method calls and thus always evaluate their argument and that they always return true or false and not their arguments.
For Sets, they perform set intersection and set union: Set#&, Set#|. For other collections (specifically Arrays), they also perform set operations: Array#&, Array#|.
For Integers, they perform BITWISE-AND of the two-complement's binary representation: Fixnum#&, Bignum#&, Fixnum#|, Bignum#|.
&& is a boolean and. It returns the second argument if the first argument is true-ish. Because 0 is true-ish in Ruby, 1 is returned.
& is a bitwise and. It compares the bit representation of the values. Because (imaging 8 bit) 00000000 (0) and 00000001 (1) have no 1 digits in common, 00000000 (0) is returned.
This page gives a good explanation of the different operators in Ruby.
&& is logical AND operator in ruby.
> a = true
> b = true
> c = false
> a && b
=> true
> a && c
=> false
& is the bitwise AND operator in ruby. Per the wikipedia article on the description for the "bitwise AND operator":
A bitwise AND takes two binary representations of equal length and
performs the logical AND operation on each pair of corresponding bits.
The result in each position is 1 if the first bit is 1 and the second
bit is 1; otherwise, the result is 0.
One is a boolean operator, the other is a bitwise operator:
# Bitwise operators
a = 78 # 01001110
b = 54 # 00110110
puts (a&b) # 00000110 = 6
puts (a|b) # 01111110 = 126
puts (a^b) # 01111000 = 120
puts (~a) # 10110001 = -79
puts (a<<2) # 00111000 = 312
puts (a>>2) # 00010011 = 19
http://www.public.traineronrails.com/courses/ruby/pages/008-rubyoperators.html
&& is logical and. Which is to say, a && b returns true if a is true and b is true. & is bitwise and. In (almost) any other language, logical and of 0 and 1 would be 0, because (almost) all other languages consider 0 to be false. But in ruby, anything except nil and false are considered to be truthy.
&& is a Logical operator which will always return a boolean value.
z It's either true if both of the values are true
true && true
and will return false if any of the value is false
false && true
Now comes to second point & Operator.
Here are two answer for the & Operator.
& is a Bitwise operator as mentioned in above answers, It compares bit representation in the form of 0 and 1.
Another Important answer is, In upgradation of Ruby 2.6 its implementation is somewhat modified.
& is represented as intersection operator
For ex:
[1, 2, 3] & [2, 3, 4]
$ [2, 3]

Find the combinations of a given encoded string using Ruby

I was asked this question during an interview and I couldn't come up with a satisfactory solution for it. Would appreciate if anybody could give some pointers.
Given a mapping like
mapping = {"A" => 1, "B" => 2, "C" => 3..... "Z" => 26}
encode("A") == "1"
encode("BA") == "21"
encode("ABC") == "123"
encode("") == ""
decode("1") == ["A"] -> 1
decode("21") == ["BA", "V"] -> 2
decode("123") == ["ABC", "JC", "AX"] -> 3
decode("012") == [] -> 0
decode("") == [""] -> 1
decode("102") == ["JB"] -> 1
numDecode(X) == len(decode(X))
numDecode("1") == 1
numDecode("21") == 2
numDecode("123") == 3
numDecode("") == 1
numDecode("102") == 1
numDecode("012") == 0
We need a numDecode method which gives the length of unique solution array.
Updated :
Given a mapping like :
mapping = {"A" => 1, "B" => 2, "C" => 3..... "Z" => 26}
Suppose we are given a string as "A" the it can be encoded as : "1"
encode("A") should return "1"
encode("BA") should return "21" as if mapping is a hash then B has a value of 2, A has a value of 1.
encode("ABC") should return "123" as mapping["A" is 1, mapping["B"] is 2, and mapping["C"] is 3.
encode("") should return "" as it is not in mapping.
Now if decode("1") is called then it should return an array with one element i.e. ["A"] as key matching with 1 as value in mapping is "A".
decode("") should return an array with empty string i.e. [""].
decode("21") should return an array ["BA", "U"] as 2 is "B", 1 is "A" and "U" is 21 in mapping.
decode("012") should return an empty array as string starts with "0" which is not in mapping keys.
decode("102") should return an array as ["JB"] as "10" is J and "2" is B.
And finally numDecode should return the count of unique decoded strings in array. So,
numDecode(X) == len(decode(X))
numDecode("1") == 1
numDecode("21") == 2
numDecode("123") == 3
numDecode("") == 1
numDecode("102") == 1
numDecode("012") == 0
This is an interesting question, and the interview technique that goes with it is most likely to see how far the critical thinking goes. A good interviewer would probably not expect a single canonically correct answer.
If you get as far as a recursive decode solution that you then enumerate, then you are doing well IMO (at least I'd hire most candidates who could demonstrate clearly thinking through a piece of recursive code at interview!)
Having said that, one key hint is that the question asks for a num_decode function, not necessarily for implementations of encode and decode.
There is a deeper understanding and structure accessible here, that can be gained from analysing the permutations and combinations. It allows you to write a num_decode function that can handle long strings with millions of possible answers, without filling memory or taking hours to enumerate all possibilities.
First note that any set of separate ambiguous encoding multiply the number of possibilities for the whole string:
1920 -> 19 is ambiguous 'AI' or 'S' -> 'AIT' or 'ST'
192011 -> 11 is also ambiguous 'AA' or 'K' -> 'AITAA', 'AITK', 'STAA', 'STK'
Here 19 has two possible interpretations, and 11 also has two. A string with both of these separate instances of ambiguous codings has 2 * 2 == 4 valid combinations.
Each independent section of ambiguous coding multiplies the size of the whole set of decode values by the number of possibilities that it represents.
Next how to deal with longer ambiguous sections. What happens when you add an ambiguous digit to an ambiguous sequence:
11 -> 'AA' or 'K' -> 2
111 -> 'AAA', 'AK', 'KA' -> 3
1111 -> 'AAAA', 'AAK', 'AKA', 'KAA', 'KK' -> 5
11111 -> 'AAAAA', 'AAAK', 'AAKA', 'AKAA', 'AKK', 'KAAA', 'KAK', 'KKA' -> 8
2,3,5,8 should look familiar, it is the Fibonacci sequence, what's going on? The answer is that adding one digit to the sequence allows all the previous combinations plus those of the sub-sequence before that. By adding a digit 1 to the sequence 1111 you can either interpret it as 1111(1) or 111(11) - so you can add together the number of possibilities in 1111 and 111 to get the number of possibilities in 11111. That is, N(i) = N(i-1) + N(i-2) which is how to construct the Fibonacci series.
So, if we can detect ambiguous coding sequences, and get their length, we can now calculate the number of possible decodes, without actually doing the decode:
# A caching Fibonacci sequence generator
def fib n
#fibcache ||= []
return #fibcache[n] if #fibcache[n]
a = b = 1
n.times do |i|
a, b = b, a + b
#fibcache[i+1] = a
end
#fibcache[n]
end
def num_decode encoded
# Check that we don't have invalid sequences, raising here, but you
# could technically return 0 and be correct according to question
if encoded.match(/[^0-9]/) || encoded.match(/(?<![12])0/)
raise ArgumentError, "Not a valid encoded sequence"
end
# The look-ahead assertion ensures we don't match
# a '1' or '2' that is needed by a '10' or '20'
ambiguous = encoded.scan(/[12]*1[789]|[12]+[123456](?![0])/)
ambiguous.inject(1) { |n,s| n * fib(s.length) }
end
# A few examples:
num_decode('') # => 1
num_decode('1') # => 1
num_decode('12') # => 2
num_decode('120') # => 1
num_decode('12121212') # => 34
num_decode('1212121212121212121212121211212121212121') # => 165580141
It is relatively short strings like the last one which foil attempts to enumerate
the possibilities directly by decoding.
The regex in the scan took a little experimentation to get right. Adding 7,8 or 9 is ambiguous after a 1, but not after a 2. You also want to avoid counting a 1 or 2 directly before a 0 as part of an ambiguous sequence because 10 or 20 have no other interpretations. I think I made about a dozen attempts at the regex before settling on the current version (which I believe to be correct, but I did keep finding exceptions to correct values most times I tested the first versions).
Finally, as an exercise, it should be possible to use this code as the basis from which to write a decoder that directly output the Nth possible decoding (or even one that enumerated them lazily from any starting point, without requiring excessive memory or CPU time).
Here's a recursive solution:
$mapping = Hash[(0..25).map { |i| [('A'.ord+i).chr,i+1] }]
$itoa = Hash[$mapping.to_a.map { |pair| pair.reverse.map(&:to_s) }]
def decode( str )
return [''] if str.empty?
return $itoa.key?(str) ? [$itoa[str]] : nil if str.length == 1
retval = []
0.upto(str.length-1) do |i|
word = $itoa[str[0..i]] or next
tails = decode(str[i+1..-1]) or next
retval.concat tails.map { |tail| word + tail }
end
return retval
end
Some sample output:
p decode('1') # ["A"]
p decode('21') # ["BA", "U"]
p decode('123') # ["ABC", "AW", "LC"]
p decode('012') # []
p decode('') # [""]
p decode('102') # ["JB"]
p decode('12345') # ["ABCDE", "AWDE", "LCDE"]
Note differences between this output and the question. E.g. The 21st letter of the alphabet is "U", not "V". etc.
#he = Hash[("A".."Z").to_a.zip((1..26).to_a.map(&:to_s))]
# => {"A"=>"1", "B"=>"2",...,"Z"=>"26"}
#hd = #he.invert # => {"1"=>"A", "2"=>"B",.., "26"=>"Z"}
def decode(str, comb='', arr=[])
return arr << s if str.empty?
# Return if the first character of str is not a key of #hd
return arr unless (c = #hd[str[0]])
# Recurse with str less the first char, s with c appended and arr
arr = decode(str[1..-1], s+c, arr)
# If the first two chars of str are a key of #hd (with value c),
# recurse with str less the first two chars, s with c appended and arr
arr = decode(str[2..-1], s+c, arr) if str.size > 1 && (c = #hd[str[0..1]])
arr
end
def num_decode(str) decode(str).size end
decode('1') # => ["A"]
decode('') # => [""].
decode('21') # => ["BA", "U"]
decode('012') # => [""]
decode('102') # => ["JB"]
decode('123') # => ["ABC", "AW", "LC"]
decode('12345') # => ["ABCDE", "AWDE", "LCDE"]
decode('120345') # => ["ATCDE"]
decode('12720132') # => ["ABGTACB", "ABGTMB", "LGTACB", "LGTMB"]
Any more? Yes, I see a hand back there. The gentleman with the red hat wants to see '12121212':
decode('12121212')
# => ["ABABABAB", "ABABABL", "ABABAUB", "ABABLAB", "ABABLL", "ABAUBAB",
"ABAUBL", "ABAUUB", "ABLABAB", "ABLABL", "ABLAUB", "ABLLAB",
"ABLLL", "AUBABAB", "AUBABL", "AUBAUB", "AUBLAB", "AUBLL",
"AUUBAB", "AUUBL", "AUUUB", "LABABAB", "LABABL", "LABAUB",
"LABLAB", "LABLL", "LAUBAB", "LAUBL", "LAUUB", "LLABAB",
"LLABL", "LLAUB", "LLLAB", "LLLL"]
num_decode('1') # => 1
num_decode('21') # => 2
num_decode('12121212') # => 34
num_decode('12912912') # => 8
This looks like a combinatorics problem, but it's also a parsing problem.
(You asked for pointers, so I'm doing this in English rather than dusting off my Ruby.)
I would do something like this:
If X is an empty string, return 1
If X is not a string composed of digits starting with a nonzero digit, return 0
If X contains no 1's or 2's, return 1 (there's only one possible parsing)
If X contains 1's or 2's, it gets a bit more complicated:
Every 1 that is not the last character in X matches both "A" and the first digit of one of the letters "J" through "S".
Every 2 that is not the last character in X and is followed by a digit less than 7 matches both "B" and the first digit of one of the letters.
Count up your 1's and 2's that meet those criteria. Let that number be Y. You have 2^Y combinations of those, so the answer should be 2^Y but you have to subtract 1 for every time you have a 1 and 2 next to each other.
So, if you haven't returned by Step 4 above, count up your 1's that aren't the last character in X, and the 2's that both aren't the last character in X and aren't followed by a 7,8,9, or 10. Let the sum of those counts be called Y.
Now count every instance that those 1's and 2's are neighbors; let that sum be called Z.
The number of possible parsings is (2^Y) - Z.
In the spirit of giving “some pointers”, instead of writing an actually implementation for numDecode let me say that the most logically straightforward way to tackle this problem is with recursion. If the string passed to numDecode is longer than one character then look at the beginning of the string and based on what you see use one or two (or zero) recursive calls to find the correct value.
And the risk of revealing too much, numDecode("1122") should make recursive calls to numDecode("122") and numDecode("22").
# just look for all singles and double as you go down and keep repeating this.. if you get to the end where the string would be 1 or 2 digets long you count 1
# IE
# 121
# 1 that's good 2 that's good 1 that's good if all good then count + 1
# 12 that's good 1 that's good ... no more doubles if all good then count + 1
# 1 that's good 21 that's good if all good then count + 1
# test this on other cases
$str = "2022"
$strlength = $str.length
$count = 0
def decode(str)
if str[0].to_i >= 1 and str[0].to_i <= 9
$count += 1 if str.length == 1
decode(str[1..-1])
end
if str[0..1].to_i >= 10 and str[0..1].to_i <= 26
$count += 1 if str.length == 2
p str.length
decode(str[2..-1])
end
end
decode($str)
p " count is #{$count}"

Resources