Why am I getting a No Method Error? - ruby

I'm new to ruby and am still having trouble parsing error messages. My method takes a string in this form:
"8, 2, 1, 6; 3, 1, 3, 2; 6, 4, 2, 7; 7, 3, 2, 4"
My goal is to split each set (offset by ;) into a subarray of an array and convert each value in the subarrays to an integer. Then, I need to print the second value in each subarray. I am getting stuck on the last part. Here is the code:
#input = "8, 2, 1, 6; 3, 1, 3, 2; 6, 4, 2, 7; 7, 3, 2, 4"
#array = []
def splitter
#input.gsub!(/\s+/, '')
#array = #input.split(';').map { |group| group.split(',') }
#array.map! { |subarray| subarray.map! {|v| v.to_i} }
#array.each { |e| print e(1) }
puts ''
end
splitter
and here is the error message:
`block in splitter': undefined method `e' for main:Object (NoMethodError)
I'm wondering if I'm not using the right form for an array of arrays.

str = "8, 2, 1, 6; 3, 1, 3, 2; 6, 4, 2, 7; 7, 3, 2, 4"
str.split(';').map { |e| e.split(',').map(&:to_i) }
#⇒ [[8, 2, 1, 6], [3, 1, 3, 2], [6, 4, 2, 7], [7, 3, 2, 4]]

Related

Ruby array processing add an unexpected nil to the new array?

New to Ruby (coming from Python) and try to experiment this exercise:
(mixed the array items by taking first, last in rotating fashion)
Expected Output to be - [1, 7, 2, 6, 3, 5, 4]. But I did not expect 'nil' at the end... The orig. array can contain even or odd size of numbers.
Can someone shed the light of this unexpected? Thanks in advance.
[Updates - re-write the example from Ruby Cookbook p.162 Array ]
nums = (1..7).to_a # [1, 2, 3, 4, 5, 6, 7]
mixed = []
#middle = nums.length / 2
#index = 0
until nums.empty?
mixed << nums.shift(). #get 1st element out
mixed << nums.pop() #get last element out
#index += 1
end
print mixed # Got [1, 7, 2, 6, 3, 5, 4, nil]
What's happening is that the total num of elements in the array is odd so the last value is put into mixed on 'shift' and then there is no element left in the array. This will solve your issue:
nums = (1..7).to_a # [1, 2, 3, 4, 5, 6, 7]
mixed = []
#middle = nums.length / 2
#index = 0
until nums.empty?
mixed << nums.shift()
mixed << nums.pop() unless nums.empty?
#index += 1
end
print mixed # Got [1, 7, 2, 6, 3, 5, 4]
Another way is: If the num of elements is odd then run the loop till n-1 and then get the last element out using shift/pop (doesn't matter if you use shift or pop at the end, you will get the same element.)
The Cookbook method can be made non-destructive (avoid modifying nums) as follows.
def doit(nums)
nums.size.times.map { |i| i.even? ? nums[i/2] : nums[-i/2] }
end
doit [1, 2, 3, 4, 5, 6, 7]
#=> [1, 7, 2, 6, 3, 5, 4]
doit [1, 2, 3, 5, 6, 7]
#=> [1, 7, 2, 6, 3, 5]
Here is another (non-destructive) way to do that.
def doit(nums)
n = nums.size/2
nums.first(n).zip(nums.last(n).reverse).flatten.tap do |a|
a << nums[n] if nums.size.odd?
end
end
doit [1, 2, 3, 4, 5, 6, 7]
#=> [1, 7, 2, 6, 3, 5, 4]
doit [1, 2, 3, 5, 6, 7]
#=> [1, 7, 2, 6, 3, 5]

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

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 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