I would like to convert a base10 number to base2 in Ruby without using the built in to_s(2) method, using recursion.
I wrote this:
def to_binary(d)
if d<1
return ""
else
return to_binary(d/2).to_s + (d%2).to_s
end
end
This would return all correct results EXCEPT 0. Is there any way to return 0 for 0 without having leading zeroes for numbers greater than 0?
You can modify your checks a bit:
def to_binary(d)
return d.to_s if [0,1].include?(d) # same as "if d == 0 || d == 1"
to_binary(d/2) + (d%2).to_s
end
to_binary(10) == "1010"
#=> true
to_binary(0) == "0"
#=> true
You could also write above method as:
def to_binary(d)
return d.to_s if [0,1].include?(d)
div,mod = d.divmod(2)
to_binary(div) + mod.to_s
end
Related
I'm just practicing and learning while loops and conditionals (not yet into arrays). I'm trying to reverse any string by concatenating letters, starting from the last letter of the word to the first. eg., for cat, start at t, then a, then c to get tac.
I don't get what's wrong in the code. I'm wondering why the 6th line ( reverse += letter) gives the error message:
6: in `+': no implicit conversion of nil into String (TypeError)
What's being nil'ed?
def is_reversed(word)
i = word.length
reverse = ""
while i > word.length || i != -1
letter = word[i]
reverse += letter
i = i - 1
end
return reverse
end
puts is_reversed("cat")
There are a few issue here but the bottom line is that you're looping wrong. You can either count up to a number or down from a number and it looks like you want to count down by starting at word.length. That's fine, but let's look and see what you're actually doing.
With while i > word.length || i != -1 you're checking each iteration that i is...greater than the length of the word? How would it get that way (you're not adding to i anywhere) and why would you want to check that?
Since you chose to count down, we want to stop when there are no letters remaining. So change your condition to while i > 0. Now we will loop only while there are letters left to go through.
There's another problem though - because indices start at 0, trying to get word[i] when i == 3 will get you nil! So you actually want to move the i = i - 1 to be the first line within your loop.
After these changes, you should have:
def is_reversed(word)
i = word.length
reverse = ""
while i > 0
i = i - 1
letter = word[i]
reverse += letter
end
return reverse
end
puts is_reversed("cat")
def is_reversed(word)
i = word.length
reverse = ""
while i > word.length || i != -1
i = i - 1
letter = word[i]
reverse += letter
end
return reverse
end
puts is_reversed("cat")
// will return 'tact'
Very first time in the loop above you're trying to find the letter you're putting the index as word.length which actually doesn't exist & hence returns nil which threw the error.
To get the last letter of a string you'll have to do i = i - 1 before you do anything else inside the loop.
Second, I think your condition is flawed. If you try to find the element at -1 in an array or string in ruby it will give you the last element.
And the first condition i > word.length will never satisfy as i's value is word.length.
So you can do something like this
def is_reversed(word)
i = word.length
reverse = ""
while i > 0
i = i - 1
letter = word[i]
reverse += letter
end
return reverse
end
puts is_reversed("cat")
//returns 'tac'
I realize this has been answered, but how about something more like:
def is_reversed(w)
w.split("").each_with_object("").with_index{ |(l,a), i| a << w[(w.length-1-i)] }
end
In console:
is_reversed('this is reversed')
=> "desrever si siht"
is_reversed('and so is this')
=> "siht si os dna"
is_reversed('antidisestablishmentarianism')
=> "msinairatnemhsilbatsesiditna"
Notes:
105 characters instead of 152
3 lines instead of 10
Uses << instead of += (which is faster)
Avoids the while i > 0 bit which is, IMO, not very idiomatic Ruby
Avoids unnecessary variable assignments (i = word.length, reverse = "", i = i - 1, and letter = word[i])
I have 2 strings:
a = "qwer"
b = "asd"
Result = "qawsedr"
Same is the length of b is greater than a. show alternate the characters.
What is the best way to do this? Should I use loop?
You can get the chars from your a and b string to work with them as arrays and then "merge" them using zip, then join them.
In the case of strings with different length, the array values must be reversed, so:
def merge_alternately(a, b)
a = a.chars
b = b.chars
if a.length >= b.length
a.zip(b)
else
array = b.zip(a)
array.map{|e| e != array[-1] ? e.reverse : e}
end
end
p merge_alternately('abc', 'def').join
# => "adbecf"
p merge_alternately('ab', 'zsd').join
# => "azbsd"
p merge_alternately('qwer', 'asd').join
# => "qawsedr"
Sebastián's answer gets the job done, but it's needlessly complex. Here's an alternative:
def merge_alternately(a, b)
len = [a.size, b.size].max
Array.new(len) {|n| [ a[n], b[n] ] }.join
end
merge_alternately("ab", "zsd")
# => "azbsd"
The first line gets the size of the longer string. The second line uses the block form of the Array constructor; it yields the indexes from 0 to len-1 to the block, resulting in an array like [["a", "z"], ["b", "s"], [nil, "d"]]. join turns it into a string, conveniently calling to_s on each item, which turns nil into "".
Here's another version that does basically the same thing, but skips the intermediate arrays:
def merge_alternately(a, b)
len = [a.size, b.size].max
len.times.reduce("") {|s, i| s + a[i].to_s + b[i].to_s }
end
len.times yields an Enumerator that yields the indexes from 0 to len-1. reduce starts with an empty string s and in each iteration appends the next characters from a and b (or ""—nil.to_s—if a string runs out of characters).
You can see both on repl.it: https://repl.it/I6c8/1
Just for fun, here's a couple more solutions. This one works a lot like Sebastián's solution, but pads the first array of characters with nils if it's shorter than the second:
def merge_alternately(a, b)
a, b = a.chars, b.chars
a[b.size - 1] = nil if a.size < b.size
a.zip(b).join
end
And it wouldn't be a Ruby answer without a little gsub:
def merge_alternately2(a, b)
if a.size < b.size
b.gsub(/./) { a[$`.size].to_s + $& }
else
a.gsub(/./) { $& + b[$`.size].to_s }
end
end
See these two on repl.it: https://repl.it/I6c8/2
I'm trying to write a method in Ruby that:
if the string length is even numbers it will return the middle two characters and,
if the string length is odd it will return only the middle character
i put together this code, but it is not working:
def the_middle(s)
if s.length % 2 == 0
return s.index(string.length/2-1) && s.index(string.length/2)
else
return s.index(string.length/2).round
end
end
I think the problem is in the syntax, not the logic, and I was hoping someone could identify where the syntax error might be.
I really appreciate your help!
Actually you have both syntax errors and logic (semantic) errors in that code.
First of all it seems you have misunderstood how the index method on string works. It does not return the character at the given index but the index of a given substring or regex as can be seen in the documentation:
Returns the index of the first occurrence of the given substring or pattern (regexp) in str.
You're also using the wrong operator to concatenate the two middle characters when the string length is even. && is the logical and operator. It's usually used for conditions and not assigments - for example in an if statement if s.length.even? && s.length > 2. The operator you want to use is + which concatenates strings.
Finally, you're using string.length but string is not defined anywhere. What you mean is probably s.length (the input parameter).
The correct solution would be more like the following:
def the_middle(s)
if s.length.even?
return s[s.length/2-1] + s[s.length/2]
else
return s[s.length/2]
end
end
I have taken the liberty to replace s.length % 2 == 0 with s.length.even? as it's more intention revealing and really the ruby way of finding out whether an integer is even or odd.
You can solve this without a conditional using String#[].
Using a range with a negative end:
def the_middle(s)
i = (s.length - 1) / 2
s[i..-i.succ]
end
Or start and length:
def the_middle(s)
a, b = (s.length - 1).divmod(2)
s[a, b + 1]
end
Both return the same results:
the_middle("a") #=> "a"
the_middle("aba") #=> "b"
the_middle("abcba") #=> "c"
the_middle("abcdcda") #=> "d"
# ^
the_middle("abba") #=> "bb"
the_middle("abccba") #=> "cc"
the_middle("abcddcda") #=> "dd"
# ^^
Try this:
def get_middle(s)
x = (s.length/2)
s.length.even? ? s[x-1..x] : s[x]
end
Since olerass already answered your doubt about the syntax, i will suggest you a less verbose solution for the question in the title:
def the_middle(s)
return s[s.length/2] if s.length.odd?
s[s.length/2-1] + s[s.length/2]
end
Same answer the syntax is just consolidated.
Format (logic result) ? ( if true this is the result) : (if false this is the result)
def get_middle(s)
num = s.length
num.even? ? ( s[num/2-1] + s[num/2]) : (s[num/2])
end
I wanted to check if a string is palindrome or not using ruby code.
I am a starter in ruby so not too aquainted with the string methods in ruby
If you are not acquainted with Ruby's String methods, you should have a look at the documentation, it's very good. Mithun's answer already showed you the basic principle, but since you are new to Ruby, there's a couple more things to keep in mind:
*) If you have a predicate method, it's customary to name it with a trailing question mark, e.g. palindrome?.
*) Boolean expressions evaluate to a boolean, so you don't need to explicitly return true or false. Hence a short idiomatic version would be
def palindrome?(str)
str == str.reverse
end
*) Since Ruby's classes are open, you could add this to the string class:
class String
def palindrome?
self == self.reverse
end
end
*) If you don't want to monkey-patch String, you can directly define the method on single object (or use a module and Object#extend):
foo = "racecar"
def foo.palindrome?
self == self.reverse
end
*) You might want to make the palindrome check a bit more complex, e.g. when it comes to case or whitespace, so you are also able to detect palindromic sentences, capitalized words like "Racecar" etc.
pal = "Never a foot too far, even."
class String
def palindrome?
letters = self.downcase.scan(/\w/)
letters == letters.reverse
end
end
pal.palindrome? #=> true
def check_palindromic(variable)
if variable.reverse == variable #Check if string same when reversed
puts "#{ variable } is a palindrome."
else # If string is not the same when reversed
puts "#{ variable } is not a palindrome."
end
end
The recursive solution shows how strings can be indexed in Ruby:
def palindrome?(string)
if string.length == 1 || string.length == 0
true
else
if string[0] == string[-1]
palindrome?(string[1..-2])
else
false
end
end
end
If reading the Ruby string documentation is too boring for you, try playing around with the Ruby practice questions on CodeQuizzes and you will pick up most of the important methods.
def is_palindrome(value)
value.downcase!
# Reverse the string
reversed = ""
count = value.length
while count > 0
count -= 1
reversed += value[count]
end
# Instead of writing codes for reverse string
# we can also use reverse ruby method
# something like this value == value.reverse
if value == reversed
return "#{value} is a palindrom"
else
return "#{value} is not a palindrom"
end
end
puts "Enter a Word"
a = gets.chomp
p is_palindrome(a)
class String
def palindrome?
self.downcase == self.reverse.downcase
end
end
puts "racecar".palindrome? # true
puts "Racecar".palindrome? # true
puts "mississippi".palindrome? # false
str= gets.chomp
str_rev=""
n=1
while str.length >=n
str_rev+=str[-n]
n+=1
end
if str_rev==str
puts "YES"
else
puts "NO"
end
> first method
a= "malayalam"
if a == a.reverse
puts "a is true"
else
puts "false"
end
> second one
a= "malayalam"
a=a.split("")
i=0
ans=[]
a.count.times do
i=i+1
k=a[-(i)]
ans << k
end
if a== ans
puts "true"
else
puts "false"
end
def palindrome?(string)
string[0] == string[-1] && (string.length <= 2 || palindrome?(string[1..-2]))
end
**Solution 1** Time complexity = O(n), Space complexity = O(n)
This solution does not use the reverse method of the String class. It uses a stack(we could use an array that only allows entry and exit of elements from one end to mimic a stack).
def is_palindrome(str)
stack = []
reversed_str = ''
str.each_char do |char|
stack << char
end
until stack.empty?
reversed_str += stack.pop
end
if reversed_str == str
return true
else
return false
end
end
` Solution 2: Time complexity = O(n), Space complexity = O(1)
def inplace_reversal!(str)
i =0
j = str.length - 1
while i < j
temp = str[i]
str[i] = str[j]
str[j] = temp
i+=1
j-=1
end
return str
end
def palindrome?(str)
return "Please pass the string" if str.nil?
str = str.downcase
str_array = str.split('')
reverse_string = str_array.each_index{ |index| str_array[str_array.count - index - 1 ] end
return ("String #{str} is not a palindrome") unless str == reverse_string.join('')
"String #{str} is palindrome"
end
I want to make a loop on a variable that can be altered inside of the loop.
first_var.sort.each do |first_id, first_value|
second_var.sort.each do |second_id, second_value_value|
difference = first_value - second_value
if difference >= 0
second_var.delete(second_id)
else
second_var[second_id] += first_value
if second_var[second_id] == 0
second_var.delete(second_id)
end
first_var.delete(first_id)
end
end
end
The idea behind this code is that I want to use it for calculating how much money a certain user is going to give some other user. Both of the variables contain hashes. The first_var is containing the users that will get money, and the second_var is containing the users that are going to pay. The loop is supposed to "fill up" a user that should get money, and when a user gets full, or a user is out of money, to just take it out of the loop, and continue filling up the rest of the users.
How do I do this, because this doesn't work?
Okay. What it looks like you have is two hashes, hence the "id, value" split.
If you are looping through arrays and you want to use the index of the array, you would want to use Array.each_index.
If you are looping through an Array of objects, and 'id' and 'value' are attributes, you only need to call some arbitrary block variable, not two.
Lets assume these are two hashes, H1 and H2, of equal length, with common keys. You want to do the following: if H1[key]value is > than H2[key]:value, remove key from H2, else, sum H1:value to H2:value and put the result in H2[key].
H1.each_key do |k|
if H1[k] > H2[k] then
H2.delete(k)
else
H2[k] = H2[k]+H1[k]
end
end
Assume you are looping through two arrays, and you want to sort them by value, and then if the value in A1[x] is greater than the value in A2[x], remove A2[x]. Else, sum A1[x] with A2[x].
b = a2.sort
a1.sort.each_index do |k|
if a1[k] > b[k]
b[k] = nil
else
b[k] = a1[k] + b[k]
end
end
a2 = b.compact
Based on the new info: you have a hash for payees and a hash for payers. Lets call them ees and ers just for convenience. The difficult part of this is that as you modify the ers hash, you might confuse the loop. One way to do this--poorly--is as follows.
e_keys = ees.keys
r_keys = ers.keys
e = 0
r = 0
until e == e_keys.length or r == r_keys.length
ees[e_keys[e]] = ees[e_keys[e]] + ers[r_keys[r]]
x = max_value - ees[e_keys[e]]
ers[r_keys[r]] = x >= 0 ? 0 : x.abs
ees[e_keys[e]] = [ees[e_keys[e]], max_value].min
if ers[r_keys[r]] == 0 then r+= 1 end
if ees[e_keys[e]] == max_value then e+=1 end
end
The reason I say that this is not a great solution is that I think there is a more "ruby" way to do this, but I'm not sure what it is. This does avoid any problems that modifying the hash you are iterating through might cause, however.
Do you mean?
some_value = 5
arrarr = [[],[1,2,5],[5,3],[2,5,7],[5,6,2,5]]
arrarr.each do |a|
a.delete(some_value)
end
arrarr now has the value [[], [1, 2], [3], [2, 7], [6, 2]]
I think you can sort of alter a variable inside such a loop but I would highly recommend against it. I'm guessing it's undefined behaviour.
here is what happened when I tried it
a.each do |x|
p x
a = []
end
prints
1
2
3
4
5
and a is [] at the end
while
a.each do |x|
p x
a = []
end
prints nothing
and a is [] at the end
If you can I'd try using
each/map/filter/select.ect. otherwise make a new array and looping through list a normally.
Or loop over numbers from x to y
1.upto(5).each do |n|
do_stuff_with(arr[n])
end
Assuming:
some_var = [1,2,3,4]
delete_if sounds like a viable candidate for this:
some_var.delete_if { |a| a == 1 }
p some_var
=> [2,3,4]