Writing Ruby inject method? - ruby

Im a bit confused at why this answer is "wrong" based on Ruby's own interpretation of the "Inject" method (for an array in this case, Im doing the "Odin Projects" projects for learning tasks)
def my_inject(start = nil)
memo = self[0] if start.nil?
for i in 0...self.length do
puts "#{memo}:#{self[i]} Results=#{yield(memo,self[i])}"
memo = yield(memo,self[i])
end
return memo
end
[5,6,7,8,9,10].my_inject { |sum, n| sum + n }
The Above returns this specifically:
5:5 Results=10
10:6 Results=16
16:7 Results=23
23:8 Results=31
31:9 Results=40
40:10 Results=50
=> 50
Which makes sense right? When no starting value is defined, the first value is used. However according to Ruby's API docs:"Inject" it should be 45....
Which doesn't make sense to me. We start with a memo of the first value and add it to the "elements" value. Which is 10 (in this case)...and so forth. Or are they saying when you DO NOT specify a value? you should skip the first array value?
I mean if I add up 5+6+7+8+9+10 yeah that is correctly 45, but if im doing what the block wants me to do, I feel like "50" makes more sense? Although obviously im wrong, im just not sure where.
I mean sure I could start the index off at 1 if we are not given a starting value...but that just seems odd.
Thanks

As people have pointed out in comments, your solution double taps the first element if no argument is provided.
Here's an implementation that is pretty straightforward, drops some unnecessary elements your solution included, and works for more than just arrays:
module Enumerable
def my_inject(memo = nil)
each { |x| memo = memo.nil? ? x : yield(memo, x) }
memo
end
end
p (1..5).my_inject(&:*) # 5 factorial => 120
p (1..5).my_inject(2, &:*) # 5 factorial doubled => 240
p %w(3 4 5).my_inject(&:+) # string concatenation => "345"
p %w(3 4 5).my_inject("hello", &:+) # concatenation w/ prefix => "hello345"
p %w(3 4 5).my_inject("howdy") { |memo, x| memo + x } # prefix and block => "howdy345"
ADDENDUM
If you want to go further and handle Symbol or String arguments as Enumerable#inject does, you need to do some preprocessing to determine what you're dealing with:
module Enumerable
def my_inject(memo = nil, sym = nil, &block)
memo = memo.to_sym if memo.is_a?(String) && !sym && !block
block, memo = memo.to_proc, nil if memo.is_a?(Symbol) && !sym
sym = sym.to_sym if sym.is_a?(String)
block = sym.to_proc if sym.is_a?(Symbol)
# Ready to rock & roll
each { |x| memo = memo.nil? ? x : block.yield(memo, x) }
memo
end
end
# A variety of test cases
p (1..4).my_inject(:*) # 4 factorial via Symbol => 24
p (1..5).my_inject('*') # 5 factorial via String => 120
p (1..6).my_inject { |memo, x| memo * x } # 6 factorial via block => 720
p (1..5).my_inject(2, &:*) # 5 factorial doubled via Proc => 240
p (1..5).my_inject(3, :*) # 5 factorial tripled via Symbol => 360
p (1..5).my_inject(4, '*') # 5 factorial quadrupled via String => 480
p %w(3 4 5).my_inject(&:+) # string concatenation via Proc => "345"
p %w(3 4 5).my_inject("hello", &:+) # prefix and Proc => "hello345"
p %w(3 4 5).my_inject("howdy") { |memo, x| memo + x } # prefix and block => "howdy345"
p %w(3 4 5).my_inject("yowza", :+) # prefix and Symbol => "yowza345"
p %w(3 4 5).my_inject("yoiks", '+') # prefix and String => "yoiks345"

Related

Method that returns result and modulo

I am trying to write a method that asks for two 2 integers, and divides the first by the second and returns the result including the remainder.
def remainder(a,b)
return a/b
return a%b
end
puts remainder(100,6)
This puts out
16
If I use this code
def remainder(a,b)
return a%b
end
puts remainder(100,6)
This puts out
4
I don't understand how to make both the modulus value and the remainder show in puts statement.
Update
Based on Simple Lime's advice I used the following code...
def remainder(a,b)
return a.divmod(b)
end
puts remainder(100,6)
Which puts
16
4
And is functioning as I had hoped.
You can return an array from the method when you need to return multiple values:
def remainder(a, b)
[a / b, a % b]
end
puts remainder(100, 6).inspect # => [16, 4]
and then you can assign each value to a different variable, if you need:
div, mod = remainder(100, 6)
puts div # => 16
puts mod # => 4
As a side note, if you are just needing both the quotient and modulus of 2 numbers, there's already a built-in function, divmod that does this, using the technique above:
100.divmod(6) # => [16, 4]

I ran into issue here with splitting array and adding it up

i am trying to find if array has 2 digits number and if i find one i want to add the two digit and make it single. then add all the numbers in array to come up with a a sum. here is my code so far. and also i am a noob and learning
class Imei
attr_accessor :Imei, :split_total1, :split_total2
def initialize(imei)
#imei = imei.to_i
#split_total1 = []
#split_total2 = []
end
def check_two_digit(num)
if num.to_s.length == 2
num = num.to_s.split(//).partition.with_index{|_,i| i.odd?}
num.each do |a, b|
a.to_i + b.to_i
end
else
num.to_i
end
end
def check_imei
if #imei.to_s.length == 15
split1, split2 = #imei.to_s.split(//).partition.with_index{|_, i| i.odd?}
split1.each do |a|
#split_total1 << check_two_digit(a.to_i * 2)
end
split2.pop
split2.each do |a|
#split_total2 << a.to_i
end
else
puts "IMEI NUMBER INVALID"
end
end
end
imei = Imei.new(123456789102222)
imei.check_imei
puts imei.split_total1.inspect
puts imei.split_total2.inspect
Find below the Luhn Algorithm I wrote in ruby
def luhn_10_valid? imei
digits = imei.reverse.chars.map(&:to_i)
digits.each_with_index.inject(0) do |sum, (digit, i)|
digit *= 2 if i.odd?
digit -= 9 if digit > 9
sum += digit
end % 10 == 0
end
For Luhn algorithm I really like the divmod method, which simplifies things
array.reverse.each_slice(2).map { |x, y|
y ||= 0
[x, (y * 2).divmod(10)]
}.flatten.inject(:+) % 10 == 0
If a contains only non-negative integers, this is one Ruby-like way to compute the sum:
a.reduce(0) {|t,i| t + (((10..99).cover? i) ? i.divmod(10).reduce(:+) : i )}
Explanation:
If i => 46, (10..99).cover?(46) => true, 46.divmod(10) => [4,6], [4,6].reduce(:+) => 10. Recall that reduce is aka inject. [4,6]reduce(:+) has the same result as (but,technically, is not 'equivalent to'):
[4,6].reduce { |u,j| u+j }
The zero initial value is needed for the first reduce, as
a[46].reduce {|t,i| t+(((10..99).cover? i) ? i.divmod(10).reduce(:+):i)}
#=> 46
which is incorrect.
If a instead contains string representations of integers and/or the integers may be negative, let me know and I'll change my answer accordingly.

Ruby: How to get the indices of the first x array elements that match a condition?

I have two huge arrays of sentences, one in German and one in English. I will search through the German sentences for sentences that contain a certain word and if they do, I will check if there is an equivalent English sentence (using a hash with connection information). However, if the user is looking for a very common word, I don't want to return every single sentence that contains it but only the first x matches and stop searching then.
If I do german_sentences.index { |sentence| sentence.include?(word) } I get only one match at a time.
If I use german_sentences.keep_if { |sentence| sentence.include?(word) } I get all matches, but also lose the index information, which is really critical for this.
I am now using a custom loop with each_with_index and break once the maximum has been reached, but I really feel that I must be missing some existing solution, at least something that gives a limited number of matches (even if not their indices)...
german_sentences
.each_index
.lazy
.select{|i| german_sentences[i].include?(word)}
.first(n)
If your need is not a one-off, you could use Module#refine, rather than monkeypatching Array). refine was added to v2.0 experimentally, then changed considerably in v. 2.1. One of the restrictions in the use of refine is: "You may only activate refinements at top-level...", which evidently prevents testing in Pry and IRB.
module M
refine Array do
def select_indices_first(n)
i = 0
k = 0
a = []
return a if n == 0
each { |x| (a << i; k += 1) if yield(x); break if k == n; i += 1 }
a
end
def select_first(n) # if you wanted this also...
k = 0
a = []
return a if n == 0
each { |x| (a << x; k += 1) if yield(x); break if k == n }
a
end
end
end
using M
sentences = ["How now brown", "Cat", "How to guide", "How to shop"]
sentences.select_indices_first(0) {|s| s.include?("How")} # => []
sentences.select_indices_first(1) {|s| s.include?("How")} # => [0]
sentences.select_indices_first(2) {|s| s.include?("How")} # => [0, 2]
sentences.select_indices_first(3) {|s| s.include?("How")} # => [0, 2, 3]
sentences.select_indices_first(99) {|s| s.include?("How")} # => [0, 2, 3]
sentences.select_first(2) {|s| s.include?("How")}
# => ["How now brown", "How to guide"]

Measure the distance between two strings with Ruby?

Can I measure the distance between two strings with Ruby?
I.e.:
compare('Test', 'est') # Returns 1
compare('Test', 'Tes') # Returns 1
compare('Test', 'Tast') # Returns 1
compare('Test', 'Taste') # Returns 2
compare('Test', 'tazT') # Returns 5
Much easier and fast due to native C binding:
gem install levenshtein-ffi
gem install levenshtein
require 'levenshtein'
Levenshtein.normalized_distance string1, string2, threshold
http://rubygems.org/gems/levenshtein
http://rubydoc.info/gems/levenshtein/0.2.2/frames
I found this for you:
def levenshtein_distance(s, t)
m = s.length
n = t.length
return m if n == 0
return n if m == 0
d = Array.new(m+1) {Array.new(n+1)}
(0..m).each {|i| d[i][0] = i}
(0..n).each {|j| d[0][j] = j}
(1..n).each do |j|
(1..m).each do |i|
d[i][j] = if s[i-1] == t[j-1] # adjust index into string
d[i-1][j-1] # no operation required
else
[ d[i-1][j]+1, # deletion
d[i][j-1]+1, # insertion
d[i-1][j-1]+1, # substitution
].min
end
end
end
d[m][n]
end
[ ['fire','water'], ['amazing','horse'], ["bamerindos", "giromba"] ].each do |s,t|
puts "levenshtein_distance('#{s}', '#{t}') = #{levenshtein_distance(s, t)}"
end
That's awesome output: =)
levenshtein_distance('fire', 'water') = 4
levenshtein_distance('amazing', 'horse') = 7
levenshtein_distance('bamerindos', 'giromba') = 9
Source: http://rosettacode.org/wiki/Levenshtein_distance#Ruby
There is an utility method in Rubygems that actually should be public but it's not, anyway:
require "rubygems/text"
ld = Class.new.extend(Gem::Text).method(:levenshtein_distance)
p ld.call("asd", "sdf") => 2
Much simpler, I'm a Ruby show-off at times...
# Levenshtein distance, translated from wikipedia pseudocode by ross
def lev s, t
return t.size if s.empty?
return s.size if t.empty?
return [ (lev s.chop, t) + 1,
(lev s, t.chop) + 1,
(lev s.chop, t.chop) + (s[-1, 1] == t[-1, 1] ? 0 : 1)
].min
end
Ruby 2.3 and later ship with the did_you_mean gem which includes DidYouMean::Levenshtein.distance. Fit for most cases and available by default.
DidYouMean::Levenshtein.distance("Test", "est") # => 1
I made a damerau-levenshtein gem where algorithms are implemented in C
require "damerau-levenshtein"
dl = DamerauLevenshtein
dl.distance("Something", "Smoething") #returns 1
I like DigitalRoss' solution above. However, as pointed out by dawg, its runtime grows on the order O(3^n), which is no good for longer strings.
That solution can be sped up significantly using memoization, or 'dynamic programming':
def lev(string1, string2, memo={})
return memo[[string1, string2]] if memo[[string1, string2]]
return string2.size if string1.empty?
return string1.size if string2.empty?
min = [ lev(string1.chop, string2, memo) + 1,
lev(string1, string2.chop, memo) + 1,
lev(string1.chop, string2.chop, memo) + (string1[-1] == string2[-1] ? 0 : 1)
].min
memo[[string1, string2]] = min
min
end
We then have much better runtime, (I think it's almost linear? I'm not really sure).
[9] pry(main)> require 'benchmark'
=> true
[10] pry(main)> #memo = {}
=> {}
[11] pry(main)> Benchmark.realtime{puts lev("Hello darkness my old friend", "I've come to talk with you again")}
26
=> 0.007071999832987785

Ruby Shoes: counting the amount of times a value occurs in an Array

I'm making a Yahtzee game in Ruby using Shoes
when I click Button "Two" the code is suppose to count the amount of times the
value 2 occurs in an array. For every instance of the value 2 that appears,
the score is incremented by 2.
This code works for a select amount of cases but on other cases like
#array = [2,1,2,2,3] # there are three 2's in the array so
the score is suppose to be 6, but instead my code returns 4... why?
button " twos " do
#array.each_with_index do |value, index|
if (#array[index] == 2)
#score = #score + 2
#points = #score + 2
end #if
end #loop end #button
This code looking better, but, in fact, it does the same thing. Maybe you should check initial values of instance variables #score and #points?
#array = [2,1,2,2,3]
#score = #points = 0
#score = #array.count(2) * 2
#points = #score
#score
=> 6
#points
=> 6
I recommend you to use Enumerable#inject method. By means of inject you can implement abstract method for counting numbers and use it everywhere in your project:
def count_of_element array, element
array.inject(0) { |count, e| count += 1 if e == element; count }
end
puts count_of_element [2,1,2,2,3], 2 # => 3
There could be even better solution – define method for Array class like this:
class Array
def count_of_element element
inject(0) { |count, e| count += 1 if e == element; count }
end
end
puts [2,1,2,2,3].count_of_element 2 # => 3
It looks even cooler. Good luck!

Resources