Comparing numbers in an array, outputting highest number - ruby

I need to write a function that takes three phone numbers in an array, adds the digits of each number seperately, and outputs the phone number with be biggest value on the screen.
Numbers are in this form [821-839-1182, 128-389-........]

You could do it like this:
arr = ['821-839-1182', '128-389-4732', '621-411-7324']
arr.max_by { |s| s.each_char.map(&:to_i).reduce(:+) }
#=> "128-389-4732"
We have:
a = arr.map { |s| s.each_char.map(&:to_i) }
#=> [[8, 2, 1, 0, 8, 3, 9, 0, 1, 1, 8, 2],
# [1, 2, 8, 0, 3, 8, 9, 0, 4, 7, 3, 2],
# [6, 2, 1, 0, 4, 1, 1, 0, 7, 3, 2, 4]]
b = a.map { |e| e.reduce(:+) }
#=> [43, 47, 31]
As the largest sum is at index 1, max_by will return the string at that index of arr. Note that '-'.to_i #=> 0.

Replace the '-'s in the phone numbers and do a radix sort to get the highest value.

Related

Ruby - Given an array of nested arrays, how to find the max only comparing the last value of each nested array?

Beginner trying to create a simple stock picker program. So far my program takes a flat array of integers representing stock prices (indices are days) and returns an array of nested arrays. Each nested array has three values [each consecutive buy day index, best sell day index, profit]. Like so:
stock_prices = [17, 2, 20, 6, 9, 15, 8, 1, 15, 15]
best_days = [[ 0, 2, 3], [ 1, 2, 18], [ 2, 5, -5],
[ 3, 5, 9], [ 4, 5, 6], [ 5, 8, 0],
[ 6, 8, 7], [ 7, 8, 14], [ 8, 9, 0]]
I would like to find the max profit day, then return an array that contains the index values of the buy and sell days of that day. In this case it would be:
absolute_best = [1, 2]
How do I iterate through an array of nested arrays but only compare the final value of each nested array?
To find the largest array element by a condition (here: the value of its 3rd element) you can use max_by in various ways.
Using array decomposition to extract the 3rd element:
best_days.max_by { |a, b, c| c }
# or
best_days.max_by { |_, _, c| c }
# or
best_days.max_by { |*, c| c }
Using the array as is and retrieve its last value:
best_days.max_by { |ary| ary.last }
# or
best_days.max_by(&:last)
All of the above return [1, 2, 18].
In addition to max_by there's also sort_by which can be used to sort the array by profit.
We can speed up the determination of the desired result as follows. Let me explain the procedure with an example that is slightly modified from the one given in the question. (I changed arr[6] from 8 to 10.)
arr = [17, 2, 20, 6, 9, 15, 10, 1, 15, 15]
days = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
We first consider selling on the last day, day 9. Should we do so, the best buy date is
days.pop
days
#=> [ 0, 1, 2, 3, 4, 5, 6, 7, 8]
days.min_by { |d| arr[d] }
#=> 7 (note arr[7] => 1)
The best pair found so far is given by
[7, 9, 14]
or, expressed as a hash,
{ buy_day: 7, sell_day: 9, net: 14}
We may now eliminate all days d strictly between 7 and 9 for which
arr[d] <= arr[9]
which is here day 8. We are now left with
days = [ 0, 1, 2, 3, 4, 5, 6, 7]
We now consider selling on new last day, day 7. The best we can do is given by
{ buy_day: 1, sell_day: 7, net: -1 }
As -1 < 14, this solution is seen to be sub-optimal. We may now eliminate all days d strictly between 1 and 7 for which
arr[d] <= arr[7]
of which there are none. We next consider
days = [ 0, 1, 2, 3, 4, 5, 6]
and selling on day 6. As the previous best buy date was 1 this obviously will be the best buy date for all sell dates between 2 and 6.
We see that the best solution when selling on day 6 is
{ buy_day: 1, sell_day: 6, net: 8 }
which again is sub-optimal. We may now eliminate all days d strictly between 1 and 6 for which
arr[d] <= arr[6]
of which there are two, days 3 and 4. We therefore next consider
days = [0, 1, 2, 5]
obtaining
{ buy_day: 2, sell_day: 5, net: 13 }
which is found to be sub-optimal (13 < 14). Day 2 cannot be eliminate (since arr[2] > arr[5]) so the new problem becomes
days = [0, 1, 2]
The solution here is
{ buy_day: 0, sell_day: 2, net: 18 }
which is found to be the new optimum. Lastly,
days = [0, 1]
is considered. As
days.pop
days = [0]
days.min_by { |d| arr[d] }
#=> 0
the solution for selling on day 1 is
{ buy_day: 0, sell_day: 1, net: -15 }
which is sub-optimal. The next problem is
days = [0]
Since the array now has only one element we are finished, with the optimal solution being
{ buy_day: 0, sell_day: 2, net: 18 }
We can write a method to implement the above approach to computing an optimal buy-sell pair as follows. Note that I have included a puts statement to illustrate the calculations being made. That statement should of course be removed.
def doit(arr,
days = arr.size.times.to_a,
sell_day = days.pop,
buy_day = days.min_by { |d| arr[d] },
best = { buy_day: nil, sell_day: nil, net: -Float::INFINITY })
puts "days=#{days}, sell_day=#{sell_day}, buy_day=#{buy_day}, best=#{best}"
return best if days.size == 1
sell_price = arr[sell_day]
candidate = sell_price - arr[buy_day]
best = { buy_day: buy_day, sell_day: sell_day, net: candidate } if
candidate > best[:net]
days.reject! { |d| d > buy_day && arr[d] <= sell_price }
sell_day = days.pop
buy_day = days.min_by { |d| arr[d] } if sell_day <= buy_day
doit(arr, days, sell_day, buy_day, best)
end
arr = [17, 2, 20, 6, 9, 15, 10, 1, 15, 15]
doit(arr)
days=[0, 1, 2, 3, 4, 5, 6, 7, 8], sell_day=9, buy_day=7,
best={:buy_day=>nil, :sell_day=>nil, :net=>-Infinity}
days=[0, 1, 2, 3, 4, 5, 6], sell_day=7, buy_day=1,
best={:buy_day=>7, :sell_day=>9, :net=>14}
days=[0, 1, 2, 3, 4, 5], sell_day=6, buy_day=1,
best={:buy_day=>7, :sell_day=>9, :net=>14}
days=[0, 1, 2], sell_day=5, buy_day=1,
best={:buy_day=>7, :sell_day=>9, :net=>14}
days=[0, 1], sell_day=2, buy_day=1,
best={:buy_day=>7, :sell_day=>9, :net=>14}
days=[0], sell_day=1, buy_day=0,
best={:buy_day=>1, :sell_day=>2, :net=>18}
#=> {:buy_day=>1, :sell_day=>2, :net=>18}

How to find the list of pairs in an array using ruby?

Input:
a = [4, 5, 5, 5, 6, 6, 4, 1, 4, 4, 3, 6, 6, 3, 6, 1, 4, 5, 5, 5]
How to list out no of pairs in an array.
Output:
9
Description
#no 1(1 pair)
#no 3(1 pair)
#no 4(2 pairs)
#no 5(3 pairs)
#no 6(2 pairs)
#so total 9 pairs
Here is another option:
a.group_by(&:itself).transform_values{ |v| v.size / 2 }.values.sum
#=> 9
How it works.
First group the elements by value:
a.group_by(&:itself) #=> {4=>[4, 4, 4, 4, 4], 5=>[5, 5, 5, 5, 5, 5], 6=>[6, 6, 6, 6, 6], 1=>[1, 1], 3=>[3, 3]}
Then transforming the keys to the pair count:
a.group_by(&:itself).transform_values{ |v| v.size / 2 } #=> {4=>2, 5=>3, 6=>2, 1=>1, 3=>1}
So, get the values of the hash:
a.group_by(&:itself).transform_values{ |v| v.size / 2 }.values #=> [2, 3, 2, 1, 1]
Finally, sum the values, which is the first line of code posted above.
arr = [4, 5, 5, 5, 6, 6, 4, 1, 4, 4, 3, 6, 6, 3, 6, 1, 4, 5, 5, 5]
hash = Hash.new(0)
arr.each { |e| hash[e] += 1 }
hash.values.reduce(0) { |s, n| s += n / 2 } // => 9
Since from what I can gather you are basically removing integers the moment they got paired once so technically it's just an integer division by two.
[1] How to count identical string elements in a Ruby array
[2] Reduce Hash Values
I have done like this, It works
b = []
a.uniq.each { |i| b.push(a.count(i)/2)}
b.sum

Is there an easiest way to increase value in a string?

I have a string a with a lot of digits, for example a = '4408 0412 3456 7893'.
I want every second value (starts from index=0) to be multiplied by 2. And I wrote this code, but it's like a too big (and wrong) and complicated:
a = '4408 0412 3456 7893'
b = a.delete(' ')
card = []
c = b.split(//)
c.each_with_index do |value, index|
card << ((value.to_i) *2) if index % 2 == 0
end
Because at the end I have an array like [8, 0, 0, 2, 6, 10, 14, 18] and but I should have another string like '8408042264106148183'.
To turn your string into an array with integers:
array = '4408 0412 3456 7893'.delete(' ').split('').map(&:to_i)
# result: [4, 4, 0, 8, 0, 4, 1, 2, 3, 4, 5, 6, 7, 8, 9, 3]
To change the array to an array where every second (?) value is doubled:
array.each_with_index {|v,i| i.even? ? array[i] = v*2 : array[i] = v}
# result: [8, 4, 0, 8, 0, 4, 2, 2, 6, 4, 10, 6, 14, 8, 18, 3]
To make a string of it again:
array.join('')
# result: "8408042264106148183"
Is this what you're looking for?

How to find highest char value in ruby?

Suppose I'm given a string "Nas". I want to select the char which has the highest integer value. How can I do this in Ruby?
My implementation involved creating a hash with the numerical value for each char:
alpha = {}
('a'...'z').zip(1. .26).each do |x| alpha[x[0]] = x[1] end
And then I'd loop through my word like so:
word.each_char do |c |
puts c
end
I have defined a method which takes two parameters, the first param is an array which specifies the "importance of a char", and second param takes a word:
def designer_pdf(h, word)
alpha = {}
('a'...'z').zip(1..26).each do |x|
alpha[x[0]] = x[1]
end
word.each_char do |c|
puts c
end
end
designer_pdf (
[1, 3, 1, 3, 1, 4, 1, 3, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5],
'abc'
)
The goal is two return the highest value from the h array based on the character from word.
For example, word: 'abc':
a = 1
b = 3
c = 1
So return 3 because b is highest.
You can do this
For zep string
p [*'a'..'z'].zip([1, 3, 1, 3, 1, 4, 1, 3, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5])
.select{|x|("zeb".chars).include?x[0]}.max_by{|x|x[1]}
output
["z", 5]
You can pass any priority array and any word as arguments:
def designer_pdf(h, word)
alpha = Hash[('a'..'z').zip(h)]
# if you want only character from word with highest priority
character = word.chars.max_by{|e| alpha[e]}
# if you want only highest char value
value = alpha[character]
# if you want both character and value
[character, value]
end
> designer_pdf([1, 3, 1, 3, 1, 4, 1, 3, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5], "abc")
#=> ["b", 3]
> designer_pdf([1, 3, 1, 3, 1, 4, 1, 3, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5], "zeb")
#=> ["z", 5]
There is no need to construct a hash.
def largest_mapped_value(word, values)
base = 'a'.ord
values[word.each_char.max_by { |c| values[c.ord-base] }.ord-base]
end
# a b c d e f g h i j k l m n o p q r s t
values = [1, 3, 1, 3, 1, 4, 1, 3, 2, 5, 6, 5, 5, 7, 5, 5, 5, 5, 5, 1,
5, 5, 5, 5, 5, 5]
# u v w x y z
%w| cat kite zebra fined a |.each { |word|
puts "#{word}: #{largest_mapped_value(word, values)}" }
cat: 1
kite: 6
zebra: 5
fined: 7
a: 1
A variant is the following.
word = "fined"
base = 'a'.ord
#=> 97
word.each_char.map { |c| values[c.ord-base] }.max
#=> 7

How to merge arrays to one array kind of respectively in ruby

I want to combine the arrays together to add the first column of all arrays, then the second columns, respectively, to the end.
My arrays :
[1,2,3,4,5]
[6,7,8,9,10]
[11,12,13,14,15]
i want result :
[1,6,11 , 2,7,12 , 3,8,13 , 4,9,14 , 5,10,15]
Suppose we have a "simple" case where the three arrays are the same length:
a = [1,2,3,4,5]
b = [6,7,8,9,10]
c = [11,12,13,14,15]
In this case, you can use Array#zip to merge the arrays in your desired way, then flatten the result into a single array:
a.zip(b, c).flatten
#=> [1, 6, 11, 2, 7, 12, 3, 8, 13, 4, 9, 14, 5, 10, 15]
However, what if a.length > b.length or b.length > c.length?
a = [1,2,3,4,5]
b = [6,7,8,9]
c = [10,11,12]
This is a little bit harder, because now Array#zip will leave you with some nil values that you presumably want to remove:
a.zip(b, c).flatten
#=> [1, 6, 10, 2, 7, 11, 3, 8, 12, 4, 9, nil, 5, nil, nil]
a.zip(b, c).flatten.compact
#=> [1, 6, 10, 2, 7, 11, 3, 8, 12, 4, 9, 5]
And finally, what if a.length < b.length or b.length < c.length?
a = [1,2,3]
b = [4,5,6,7]
c = [8,9,10,11,12]
This is again a bit harder. Now, you'll presumably want to pad the arrays with as many nils as needed, and then perform the same operation as above:
max_length = [a,b,c].map(&:length).max
def padded_array(array, size)
array.dup.fill(nil, array.length, size)
end
padded_array(a, max_length).zip(
padded_array(b, max_length), padded_array(c, max_length)
).flatten.compact
So the complexity of your final answer depends on what arrays you are dealing with, and how far you need to go with accounting for edge cases.
a = [1,2,3,4,5]
b = [6,7,8,9,10]
c = [11,12,13,14,15]
((a.zip b).zip c).flatten.compact
=> [1, 6, 11, 2, 7, 12, 3, 8, 13, 4, 9, 14, 5, 10, 15]

Resources