Finding palindromic numbers in Ruby - ruby

So, I'm doing Project Euler to solidify my Ruby skills. I'm on problem #4, which reads:
A palindromic number reads the same
both ways. The largest palindrome made
from the product of two 2-digit
numbers is 9009 = 91 * 99.
Find the largest palindrome made from
the product of two 3-digit numbers.
First, I'm trying to verify my code using the information from the first paragraph. I've defined a palindrome function as so:
def palindrome?(blah)
string = blah.to_s
string.reverse == string
end
My code looks like:
array = (90..99).to_a
array = array.map{|u| array.map{|y| u*y}}
array = array.sort
array = array.select{|u| palindrome?(u)}
puts array
The program doesn't output anything. If I do the following:
array = (90..99).to_a
array = array.map{|u| array.map{|y| u*y}}
array = array.sort
#array = array.select{|u| palindrome?(u)}
puts array
I get a long series of unsorted four-digit numbers, so I guess it's ignoring the sort. Finally, if I simply do:
#array = (90..99).to_a
#array = array.map{|u| array.map{|y| u*y}}
#array = array.sort
array = [7447, 9009, 3551, 2419]
array = array.select{|u| palindrome?(u)}
puts array
I get 7447 and 9009, like I should. Why is this happening?
I'm using 1.8.6, because that's the only version available on this Windows machine.

This line of yours
array = array.map{|u| array.map{|y| u*y}}
returns a nested array, you should unwrap.
Hints: (but I'm not going to tell you how)
You probably don't need sort on the intermediary value
You need to remove duplicates
Tips:
next time, run your code in the interactive interpreter, that way you'll see the result of each line of code.

You can use something like this
new_arr = array.inject([]) { |a,u| a += array.map { |y| u*y } }
instead of
array = array.map{|u| array.map{|y| u*y}}
it returns a nested "[ [8100,..],[],[] ] " type of array. So thats the reason why your code doesn't work

This looks more understandable:-
#Steps
# Define a method for palindrome
# List out all 3-digit numbers
# Multiply each numbers by each numbers
# List out all palindrome numbers
# Choose the largest (max) palindrome number
def is_a_palindrome?(n)
n == n.to_s.reverse.to_i
end
def problem_four
palindrome = [ ]
array = 111.upto(999)
array.each do |x|
array.each do |y|
multiply = x * y
if is_a_palindrome?(multiply)
palindrome << multiply
end
end
end
palindrome.max
end
puts problem_four
#$ ruby problem_four.rb
#906609

Find the largest palindrome made from the product of two 3-digit numbers.
I have made this solution, I hope this will help some newbie
to=999
from=100
palindromes=[]
for i in from..to do
for j in 1..to do
k=i*j
palindromes << k if k.to_s==k.to_s.reverse
end
end
palindromes.max #this will return 906609

Related

How can I store my outcome into an array in ruby language?

My teacher asked me to write a Ruby program that contain a loop and in each iteration it randomly makes a choice: head (represented by 1) or tail (represented by 0), and stores the outcome (0 or 1) in an array. I am not sure how to store my outcome into an array and this is my code
p "Select a number between 50 to 100"
x = gets.to_i
i = 0
array[x]
while i < x
a = rand(0..1)
array.push(a)
i += 1
end
Hay, may you can try the following:
number_of_times = gets.to_i
array = []
number_of_times.times do
random_result = rand(0..1)
array.push(random_result)
end
or (like the comments)
n = gets.to_i
array = n.times.map{ rand(0..1) }
After executing this, array will have the result of all randomized options.
Note1: You don't need to initialize array with the width, you can just initialize the array and push elements to him.
Note2: No problems with your while operator, but in ruby, you have the .times iterator, is more legible for this case.
You can leverage Ruby's Array block constructor to allocate and initialize your array in a one-liner:
array = Array.new(n) { rand(0..1) } # sample result: [0, 0, 1, 0, 1, 0] for n = 6
The argument n determines the size of the array, and the block argument is used to initialize each of the n elements.

Permutations of strings takes too long to solve

I'm creating an array of permutated and unique letters in a string, only to sort them alphabetically and find the middle element in the set.
def middle_permutation(string)
length = string.length
permutation_set = string.split("").permutation(length).to_a.map{|item| item.join}.sort
permutation_set.length.even? ? permutation_set[(permutation_set.length)/2-1] : permutation_set[(permutation_set.length/2)+1]
end
For example:
middle_permutation("zxcvbnmasd") should equal "mzxvsndcba"
Even for small strings (N >=10), the calculations take pretty long to finish, and I can forget about anything double that; is there a quicker way?
I'm assuming the letters are unique, as in the OP's question.
Sort
Pluck the middle letter of the sorted string (rounded down). This is the first letter of the middle permutation.
If the original list had an even number of letters, the rest of the permutation is the reverse sort of the remaining letters.
If not, take the middle letter again. Now the rest of the result is the reverse sort of the remaining letters.
The method below returns the desired permutation directly, without iterating through permutations.
The asker has stated that the string contains no duplicated letters, which is a requirement for this method. I assume the characters of the string are sorted. If they are not, the creation of a sorted string would be the first step:
str = "ebadc".chars.sort.join
#=> "abcde"
Code
def mid_perm(str)
return mid_perm_even_length_strings(str) if str.size.even?
first_char_index = str.size/2
str[first_char_index] << mid_perm_even_length_strings(str[0,first_char_index] +
str[first_char_index+1..-1])
end
def mid_perm_even_length_strings(str)
first_char_index = str.size/2-1
str[first_char_index] + (str[0,first_char_index] + str[first_char_index+1..-1]).reverse
end
Examples
mid_perm 'abcd'
#=> "bdca"
mid_perm 'abcde'
#=> "cbeda"
mid_perm 'abcdefghijklmnopqrstuvwxyz'
#=> "mzyxwvutsrqponlkjihgfedcba"
Explanation
Let's start by defining a method to produce permutations of the letters of a string.
def perms(str)
str.chars.permutation(str.size).map(&:join)
end
Strings containing an even number of characters
Consider
a = perms "abcd"
#=> ["abcd", "abdc", "acbd", "acdb", "adbc", "adcb",
# "bacd", "badc", "bcad", "bcda", "bdac", "bdca",
# "cabd", "cadb", "cbad", "cbda", "cdab", "cdba",
# "dabc", "dacb", "dbac", "dbca", "dcab", "dcba"]
a contains 4! #=> 4*3*2 => 24 elements, 4 being the length of the string.
Notice that since the characters in perms' argument are sorted, the array returned is also sorted1.
a == a.sort #=>true
As a.size #=> 24, the "middle" element is either a[11] #=> "bdca" or a[12] #=> "cabd" (where 11 = (24-1)/2 and 12 = 24/2), depending on how we want to round. The question stipulates that, for even-length strings, we are to round down, so that would be "bdca".
Now let's slice a into str.size equal arrays, each containing a.size/str.size #=> 24/4 => 6 elements:
b = a.each_slice(a.size/str.size).to_a
#=> [["abcd", "abdc", "acbd", "acdb", "adbc", "adcb"],
# ["bacd", "badc", "bcad", "bcda", "bdac", "bdca"],
# ["cabd", "cadb", "cbad", "cbda", "cdab", "cdba"],
# ["dabc", "dacb", "dbac", "dbca", "dcab", "dcba"]]
The desired element is therefore
b[(a.size/str.size-1)/2-1][-1]
#=> "bdca"
This value can be computed more directly as follows.
first_char_index = str.size/2-1
#=> 1
first_char = str[first_char_index]
#=> "b"
remaining_chars = (str[0,first_char_index] + str[first_char_index+1..-1]).reverse
#=> "dca"
first_char + remaining_chars
#=> "bdca"
The same logic applies to all strings having an even number of characters. We therefore can write the method mid_perm_even_length_strings shown in the Code section above.
For example (for a 12-character string)
mid_perm_even_length_strings 'abcdefghijkl'
#=> "flkjihgedcba"
Strings containing an odd number of characters
Now consider
str = "abcde"
a = perms str
#=> ["abcde", "abced", "abdce", "abdec", "abecd", "abedc",
# "acbde", "acbed", "acdbe", "acdeb", "acebd", "acedb",
# "adbce", "adbec", "adcbe", "adceb", "adebc", "adecb",
# "aebcd", "aebdc", "aecbd", "aecdb", "aedbc", "aedcb",
# "bacde", "baced", "badce", "badec", "baecd",..., "bedca",
# "cabde", "cabed", "cadbe", "cadeb", "caebd", "caedb",
# "cbade", "cbaed", "cbdae", "cbdea", "cbead", "cbeda",
# "cdabe", "cdaeb", "cdbae", "cdbea", "cdeab", "cdeba",
# "ceabd", "ceadb", "cebad", "cebda", "cedab", "cedba",
# "dabce", "dabec", "dacbe", "daceb", "daebc",..., "decba",
# "eabcd", "eabdc", "eacbd", "eacdb", "eadbc",..., "edcba"]
Here the permutation contains 5! #=> 100 elements, in 5 blocks of 20. (Again, a.each_cons(2).all? { |s1,s2| s1 < s2 } #=> true.)
The middle element of a is clearly the middle element of the block of elements that begin with
str[str.size/2] #=> "c"
That block would be the array
b = a.each_slice(a.size/str.size).to_a[str.size/2]
#=> ["cabde", "cabed", "cadbe", "cadeb", "caebd", "caedb",
# "cbade", "cbaed", "cbdae", "cbdea", "cbead", "cbeda",
# "cdabe", "cdaeb", "cdbae", "cdbea", "cdeab", "cdeba",
# "ceabd", "ceadb", "cebad", "cebda", "cedab", "cedba"]
which would be 'c' plus the middle element of the array
["abde", "abed", "adbe", "adeb", "aebd", "aedb",
"bade", "baed", "bdae", "bdea", "bead", "beda",
"dabe", "daeb", "dbae", "dbea", "deab", "deba",
"eabd", "eadb", "ebad", "ebda", "edab", "edba"]
That array is merely the permutations of the string "abde". Since that string contains an even number characters, its middle element is
mid_perm_even_length_strings 'abde'
#=> "beda"
It follows that the middle element of the permutations of the letters of "abcde" is therefore
'c' + 'abde'
#=> "cabde"
This clearly applies to all strings containing an odd number of characters.
1. The doc for Array#permutation states, "The implementation makes no guarantees about the order in which the permutations are yielded.". We therefore might need to tack .sort to the end of the operative line of perms, but with Ruby v2.4 (and I suspect, earlier versions) that is, in fact not necessary here.
I was able to compact it like this:
def middle_permutation(string)
list = string.chars.permutation.map(&:join).sort
list[list.length / 2 - (list.length.even? ? 1 : 0)]
end
Which yields:
middle_permutation('zxcvbnmasd')
# => "mzxvsndcba"
You don't need to generate all permutations. Just find overall number of permutations as PN = N! where N is string (of different chars) length and calculate only needed PN/2-th permutation by its number - for example, using this approach
public static int[] perm(int n, int k)
{
int i, ind, m=k;
int[] permuted = new int[n];
int[] elems = new int[n];
for(i=0;i<n;i++) elems[i]=i;
for(i=0;i<n;i++)
{
ind=m%(n-i);
m=m/(n-i);
permuted[i]=elems[ind];
elems[ind]=elems[n-i-1];
}
return permuted;
}
So it turns out there are two tracks to this, odd strings and even strings.
For odd strings, you take out the middle character Element of the sorted array and the one before it, in that order. When you do that you have two remaining arrays, the one the right and left, both alphabetically sorted. You tack on elements of the right array, starting with the last element, then do the same for the one on the left.
For even strings, Do the same but only take one character in the first step: the (N/2) element.
Here's my solution:
def middle_permutation(string)
string_array = string.chars.sort
mid_string = []
length = string.length
if length.even?
mid_string << string_array[length/2-1]
string_array.delete_at(length/2-1)
(mid_string << string_array.reverse).flatten.join
else
mid_string << string_array[(length/2)-1..length/2].reverse
string_array.slice!((length/2)-1, 2)
(mid_string << string_array.reverse).flatten.join
end
end

Sort Integer Array Ruby

Have the function PermutationStep (num) take the num parameter being passed and return the next number greater than num using the same digits. For example: if num is 123 return 132, if it's 12453 return 12534. If a number has no greater permutations, return -1 (ie. 999)
Here's my code. I'd like to sort an array of large integers in numerical order. Using the regular sort method doesn't give the right order for some numbers. Is there a sort_by structure that I can replace 'sort' with in my code below?
def PermutationStep(num)
num = num.to_s.split('').map {|i| i.to_i}
permutations = num.permutation.to_a.sort #<= I want to sort by numerical value here
permutations.each_with_index do |n, idx|
if n == num
if n == permutations[-1]
return -1
else
return permutations[idx+1].join.to_i
end
end
end
end
For example, 11121. When I run the code it gives me 11121.I want the next highest permutation, which should be 12111.
Also, when I try { |a,b| b <=> a }, I also get errors.
You can pass a block to sort.
num.permutation.to_a.sort { |x, y| x.to_i <=> y.to_i }
This SO thread may be of some assistance: How does Array#sort work when a block is passed?
num.permutation.to_a is an array of arrays, not an array of integers, which causes the result not what you expected.
Actually you don't need to sort since you only need the minimum integer that is bigger than the input.
def PermutationStep(num)
nums = num.to_s.split('')
permutations = nums.permutation.map{|a| a.join.to_i}
permutations.keep_if{|n| n > num}.min || -1
end
puts PermutationStep(11121) # 11211
puts PermutationStep(999) # -1
Call to_i before your sort the permutations. Once that is done, sort the array an pick the first element greater than your number:
def PermutationStep(num)
numbers = num.to_s.split('')
permutations = numbers.permutation.map { |p| p.join.to_i }.sort
permutations.detect { |p| p > num } || -1
end
You don't need to consider permutations of digits to obtain the next higher number.
Consider the number 126531.
Going from right to left, we look for the first decrease in the digits. That would be 2 < 6. Clearly we cannot obtain a higher number by permuting only the digits after the 2, but we can obtain a higher number merely by swapping 2 and 6. This will not be the next higher number, however.
We therefore look for the smallest digit to the right of 2 that is greater than 2, which would be 3. Clearly, the next higher number will begin 13 and will have the remaining digits ordered smallest to largest. Therefore, the next higher number will be 131256.
You can easily see that the next higher number for 123 is 132, and for 12453 is 12534.
The proof that procedure is correct is easily established by induction, first showing that it is correct for numbers with two digits, then assuming it is correct for numbers with n>=2 digits, showing it is correct for numbers with n+1 digits.
It can be easily implemented in code:
def next_highest(n)
a = n.to_s.reverse.split('').map(&:to_i)
last = -Float::INFINITY
x,ndx = a.each_with_index.find { |d,i| res = d<last; last=d; res }
return nil unless x
swap_val = a[ndx]
swap_ndx = (0...ndx).select { |i| a[i] > swap_val }.min_by{ |i| a[i] }
a[ndx], a[swap_ndx] = a[swap_ndx], swap_val
a[0...ndx] = a[0...ndx].sort.reverse
a.join.reverse
end
next_highest(126531) #=> "131256"
next_highest(109876543210) #=> "110023456789"

Why is this happening with base converter?

I am building a number base converter. Here is my code:
def num_to_s(num, base)
results = []
remainders = []
while base <= num
result = num / base #divide the initial value of num
num = result #put that back in num so you can do it again
results << num #push into array, then map for remainders
end
remainders << results.map{|i| result = i % base} #get remainders (doesn't shovel first one?)
first_remainder = num % base #since the first remainder isn't getting recorded
return (first_remainder.to_s + remainders.to_s).reverse
end
num_to_s(13346, 7)
The modulo that gathers the remainders from the results array is not picking up the remainder from the very first iteration of that array. I remedied the skip by giving the first modulo operation it's own separate variable, which may be a cheap hack but it works. Why is this happening? And is there a better way to fix it (without some complete overhaul)?
It needs to convert up to base 16. I am aware that this will not convert base 16 yet because of the letters involved, I'll figure that when I get to it. But I am open to suggestions on that as well.
The very first operation you do is to modulo number by base. That’s why the initial is not kept. So, the easiest way to keep it is just to put it into an array initially:
def num_to_s (num, base)
results = [num] # keep the initial
while base <= num
num /= base # divide the initial value of num
results << num # push into array, then map for remainders
end
# reverse an array and only then join it into string
results.map {|i| i % base}.reverse.join
end
puts num_to_s(13346, 7)
#⇒ 53624

Operation on values in a hash: Ruby

My input is:
aaabbbb
I have written the following code:
here = string.split(//)
count = Hash.new(0)
there = here.each {|a|
count[a] += 1
}
This gives me the following output:
{"a"=>3, "b"=>4}
Now, I want to check the number of odd values in my hash for example if my output had been:
{"a"=>3, "b"=>4, "c"=>3}
Then the answer should be:
2
Note: I am doing this to check if aaabbbb can form an anagram which could be a palindrome. So if there are more than 2 characters with odd value then it would not form a palindrome and vice-versa.
Just use count method.
count.count{|k,v| v.odd?}
You can use Hash#values to get an array of values. Then count the number of odd elements in it:
res = {"a"=>3, "b"=>4, "c"=>3}
res.values.count(&:odd?)
#=> 2
You can do that by using iterating over each_value of count and then select and then check the length
count.each_value.select { |n| n.odd? }.length

Resources