How to find highest char value in ruby? - 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

Related

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?

Transform one list into another [duplicate]

This question already has answers here:
Algorithm: optimal way to rearrange a list from one order to another?
(4 answers)
Closed 4 years ago.
Given two lists, for example:
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
b = [2, 4, 6, 7, 0, 1, 3, 5, 8, 9]
I wish to find a series of moves which will transform list a into list b, where each move is an operation:
move(from_index, to_index)
which moves the element at location from_index and places it at location to_index. So if:
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
then the operation move(3,1) on the list a will transform a into:
a = [0, 3, 1, 2, 4, 5, 6, 7, 8, 9]
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
b = [2, 4, 6, 7, 0, 1, 3, 5, 8, 9]
move(0, 8)
a = [1, 2, 3, 4, 5, 6, 7, 0, 8, 9]
move(0, 8)
a = [2, 3, 4, 5, 6, 7, 0, 1, 8, 9]
move(1, 8)
a = [2, 4, 5, 6, 7, 0, 1, 3, 8, 9]
move(2, 8)
a = [2, 4, 6, 7, 0, 1, 3, 5, 8, 9]
a==b
Hopefully that's what you're looking for.
Basically, start with the left- most element and move it to where it should be. For example, I took 0 and placed it right after the value that it is supposed to eventually end up behind, which is 7. I continued moving from left to right until all of the elements were in the desired order.
I'd iterate over the second sequence (the sorted list) and swap items in the first. I wrote this pseudo-code in python:
>>> a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> b = [2, 4, 6, 7, 0, 1, 3, 5, 8, 9]
>>> def swap(seq, i, j):
... a = seq[i]
... seq[i] = seq[j]
... seq[j] = a
...
>>> for index_in_b, value in enumerate(b):
... index_in_a = a.index(value)
... if index_in_b != index_in_a:
... swap(a, index_in_a, index_in_b)
... print('move {} to {}'.format(index_in_a, index_in_b))
move 0 to 2
move 1 to 4
move 2 to 6
move 3 to 7
move 4 to 6
move 5 to 6
move 6 to 7
In this case I'm moving the items in the first sequence by swapping them.
Update
We can slightly improve the performance in python by removing the move inside swap function and also removing the function call. Here is a performance comparison:
import timeit
s1 = """
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
b = [2, 4, 6, 7, 0, 1, 3, 5, 8, 9]
def swap(seq, i, j):
a = seq[i]
seq[i] = seq[j]
seq[j] = a
for index_in_b, value in enumerate(b):
index_in_a = a.index(value)
if index_in_b != index_in_a:
swap(a, index_in_a, index_in_b)"""
s2 = """
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
b = [2, 4, 6, 7, 0, 1, 3, 5, 8, 9]
for index_in_b, value in enumerate(b):
index_in_a = a.index(value)
if index_in_b != index_in_a:
a[index_in_a], a[index_in_b] = a[index_in_b], a[index_in_a]"""
# on an i7 macbook pro
timeit.timeit(s1)
4.087386846542358
timeit.timeit(s2)
3.5381240844726562
Slightly better, but for sure there are better ways to achieve this.

How can I filter an array based a hash of arrays while considering each value unique?

In a project of mine, I'm trying to filter newly gathered information that also contains all the data from the previous request. With this filtered data, I'd like to add it to the old data as a new array. New data comes in as an array, and the old data is kept stored in a hash of arrays.
I've tried a number of different methods to remove all past data points from the current data unsuccessfully. An important detail here is that the new data may contain duplicate values that match older ones, but are technically new and should be treated as unique.
Here's an example data set:
x = {
'a' => [],
'b' => [1],
'c' => [],
'd' => [2, 3, 1, 5, 6, 3]
}
y = [0, 2, 3, 5, 1, 5, 6, 3, 1, 10, 7]
z = [0, 5, 10, 7]
x is the old data and y is the new data. The desired output of the filtering would be z that would then be added to x giving us:
x = {
'a' => [],
'b' => [1],
'c' => [],
'd' => [2, 3, 1, 5, 6, 3]
'e' => [0, 5, 10, 7]
}
I would need to continue repeating this for a bit based on some other criteria.
The main hurdle here is getting the filtering done correctly and has been proving difficult for me. Here's a list of some of the things I've tried:
I've tried iterating across the hash's keys and then simply subtracting the arrays, but that doesn't work properly as it gets rid of duplicates too, unfortunately.
irb(main):024:0> d = [2, 3, 1, 5, 6, 3]
=> [2, 3, 1, 5, 6, 3]
irb(main):025:0> y = [0, 2, 3, 5, 1, 5, 6, 3, 1, 10, 7]
=> [0, 2, 3, 5, 1, 5, 6, 3, 1, 10, 7]
irb(main):026:0> y - d
=> [0, 10, 7]
I've tried unions
irb(main):029:0> y | d
=> [0, 2, 3, 5, 1, 6, 10, 7]
and intersections. (which are definitely wrong)
irb(main):030:0> y & d
=> [2, 3, 5, 1, 6]
I tried (unsuccessfully) implementing the following from the second comment here
class Array
def delete_elements_in(ary)
ary.each do |x|
if index = index(x)
delete_at(index)
end
end
end
I've also tried reject!
irb(main):057:0> x = { 'a' => [], 'b' => [1], 'c' => [], 'd' => [2, 3, 1, 5, 6, 3] }
=> {"a"=>[], "b"=>[1], "c"=>[], "d"=>[2, 3, 1, 5, 6, 3]}
irb(main):058:0> y = [0, 2, 3, 5, 1, 5, 6, 3, 1, 10, 7]
=> [0, 2, 3, 5, 1, 5, 6, 3, 1, 10, 7]
irb(main):059:0> x.each_key { |key| y.reject! { |v| a[key].index(v) } }
=> {"a"=>[], "b"=>[1], "c"=>[], "d"=>[2, 3, 1, 5, 6, 3]}
irb(main):060:0> y
=> [0, 10, 7]
A more recent attempt I tried creating a new array from all of x's values and then using that against y, also unsuccessfully. I had just recently thought of trying to keep an array of 'seen' numbers, but I'm still stuck for items that actually need to be removed even though duplicate.
Throughout all this, I've been unable to get [0, 5, 10, 7] as a result.
Halp!
Here's something that might work for you:
>> existing = x.values.flatten
#> [1, 2, 3, 1, 5, 6, 3]
>> z = y.dup # This avoids altering the original `y` array
>> existing.each { |e| z.delete_at(z.index(e)) if z.index(e) }
>> z
#> [0, 5, 10, 7] # z now contains the desired result
>> x['e'] = z
>> pp x
{"a"=>[],
"b"=>[1],
"c"=>[],
"d"=>[2, 3, 1, 5, 6, 3],
"e"=>[0, 5, 10, 7]}
Here's the whole thing in a single method:
def unique_array_filter(hash, new_array)
existing = hash.values.flatten
next_key = hash.keys.max.next
temp = new_array.dup
existing.each { |e| temp.delete_at(temp.index(e)) if temp.index(e) }
hash[next_key] = temp
hash
end
>> unique_array_filter(x, y)
#> {"a"=>[], "b"=>[1], "c"=>[], "d"=>[2, 3, 1, 5, 6, 3], "e"=>[0, 5, 10, 7]}
x.merge(x.keys.max.next => y.difference(x.values.flatten))
#=> {"a"=>[], "b"=>[1], "c"=>[], "d"=>[2, 3, 1, 5, 6, 3], "e"=>[0, 5, 10, 7]}
where Array#difference is defined as follows.
class Array
def difference(other)
h = other.each_with_object(Hash.new(0)) { |e,h| h[e] += 1 }
reject { |e| h[e] > 0 && h[e] -= 1 }
end
end
See the link for an explanation of Array#difference.

Ruby correct code for nested loop for Euler 8

Find the thirteen adjacent digits in the 1000-digit number that have the greatest product. What is the value of this product?
https://projecteuler.net/problem=8
data = '''73167176531330624919225119674426574742355349194934
96983520312774506326239578318016984801869478851843
85861560789112949495459501737958331952853208805511
12540698747158523863050715693290963295227443043557
66896648950445244523161731856403098711121722383113
62229893423380308135336276614282806444486645238749
30358907296290491560440772390713810515859307960866
70172427121883998797908792274921901699720888093776
65727333001053367881220235421809751254540594752243
52584907711670556013604839586446706324415722155397
53697817977846174064955149290862569321978468622482
83972241375657056057490261407972968652414535100474
82166370484403199890008895243450658541227588666881
16427171479924442928230863465674813919123162824586
17866458359124566529476545682848912883142607690042
24219022671055626321111109370544217506941658960408
07198403850962455444362981230987879927244284909188
84580156166097919133875499200524063689912560717606
05886116467109405077541002256983155200055935729725
71636269561882670428252483600823257530420752963450'''
The code is:
def largest_product_series
mx = 0
arr = data.split("")
arr.map!{ |x| x.to_i}
(arr.size - 13).times do |i|
0.upto(13) do |c|
result = arr.inject() {|sum,c | sum * arr[i + c]}
puts result
if result >= mx
mx = result
end
end
end
#puts "#{mx}"
mx
end
It is actually from Euler project 8 which I am working on. please help me to correct my code and give me some advise, I keep getting a hundred digit output.
A Rubyish way of doing that is as follows.
data = '73167176531330624919225119674426574742355349194934' +
'96983520312774506326239578318016984801869478851843' +
'85861560789112949495459501737958331952853208805511' +
'12540698747158523863050715693290963295227443043557' +
'66896648950445244523161731856403098711121722383113' +
'62229893423380308135336276614282806444486645238749' +
'30358907296290491560440772390713810515859307960866' +
'70172427121883998797908792274921901699720888093776' +
'65727333001053367881220235421809751254540594752243' +
'52584907711670556013604839586446706324415722155397' +
'53697817977846174064955149290862569321978468622482' +
'83972241375657056057490261407972968652414535100474' +
'82166370484403199890008895243450658541227588666881' +
'16427171479924442928230863465674813919123162824586' +
'17866458359124566529476545682848912883142607690042' +
'24219022671055626321111109370544217506941658960408' +
'07198403850962455444362981230987879927244284909188' +
'84580156166097919133875499200524063689912560717606' +
'05886116467109405077541002256983155200055935729725' +
'71636269561882670428252483600823257530420752963450'
def prod(arr)
arr.reduce(1, :*)
end
arr = data.each_char.map(&:to_i).each_cons(13).max_by { |a| prod(a) }
#=> [5, 5, 7, 6, 6, 8, 9, 6, 6, 4, 8, 9, 5]
[arr.join, prod(arr)]
#=> ["5576689664895", 23514624000]
The steps are as follows. Suppose
data = '731671765313326'
(data.size #=> 15). Then
b = data.each_char.map(&:to_i)
#=> [7, 3, 1, 6, 7, 1, 7, 6, 5, 3, 1, 3, 3, 2, 6]
c = b.each_cons(13)
#=> #<Enumerator: [7, 3, 1, 6, 7, 1, 7, 6, 5, 3, 1, 3, 3, 2, 6]:each_cons(13)>
We can see the elements that will be generated by this enumerator by converting it to an array:
c.to_a
#=> [[7, 3, 1, 6, 7, 1, 7, 6, 5, 3, 1, 3, 3],
# [3, 1, 6, 7, 1, 7, 6, 5, 3, 1, 3, 3, 2],
# [1, 6, 7, 1, 7, 6, 5, 3, 1, 3, 3, 2, 6]]
arr = c.max_by { |a| prod(a) }
#=> [7, 3, 1, 6, 7, 1, 7, 6, 5, 3, 1, 3, 3]
This was obtained by computing:
[prod [7, 3, 1, 6, 7, 1, 7, 6, 5, 3, 1, 3, 3],
prod [3, 1, 6, 7, 1, 7, 6, 5, 3, 1, 3, 3, 2],
prod [1, 6, 7, 1, 7, 6, 5, 3, 1, 3, 3, 2, 6]].max
#=> [5_000_940, 1_428_840, 2_857_680].max
#=> 5000940
The last step is to return the array
[arr.join, prod(arr)]
#=> [[7, 3, 1, 6, 7, 1, 7, 6, 5, 3, 1, 3, 3].join,
#=> prod([7, 3, 1, 6, 7, 1, 7, 6, 5, 3, 1, 3, 3])]
#=> ["7316717653133", 5000940]

Resources