What does this Ruby code using inject method do? - ruby

class Array
def sum(start = 0)
inject(start, &:+)
end
end
Please explain me the use of this code.
Test case with input and output will be helpful.
Thank you.

It sums up all the elements that are kept inside you array. start is a value to which sum is added. for example for array foo = [1, 4]; foo.inject(10, &:+) will return 15 (10 + 1 + 4).
&:+ is telling what operation should be called on each element in array;
it's the same as you would give your own callback for example
foo.inject(10) do |current_sum, current_element|
current_sum = current_sum + current_element #can be written current_sum += current_element
current_sum
end

Related

Is this the correct implementation for insertion sort in ruby

I'm trying to do array practice problems and I'm working on insertion sort right now. I'm wondering whether this code is clear and readable. To me it looks kind of confusing, if anyone has a cleaner way(easier to understand) to implement this can you help me please?
def insertion_sort(arr)
(1...arr.length).each do |i| #iterate through array go through every element
j=i-1 #to check all elements behind i
while(j>=0&&arr[i]<arr[j]) #while not out bounds and current element is less than previous
temp=arr[i] #3 lines to switch arr[i] and arr[j]
arr[i]=arr[j]
arr[j]=temp
i=j #keep track of where i is
j-=1 #decrease j by 1 to check the previous element
end
end
return arr
end
This isn't necessary in ruby:
temp=arr[i] #3 lines to switch arr[i] and arr[j]
arr[i]=arr[j]
arr[j]=temp
because you can do multiple assignment like this:
a,b = 1,2
which is the same as:
a = 1
b = 2
which means you can switch the values of variables like this:
a,b = b,a
or in your case:
arr[i],arr[j] = arr[j],arr[i]
This probably has its own issues, but you can see a couple simplifications here to hopefully make the code more readable.
class Array
def swap(a, b)
self[a], self[b] = self[b], self[a]
end
end
def insertion_sort(arr)
(1...arr.size).each do |i|
i.downto(1).each do |j|
break if arr[j] >= arr[j - 1]
arr.swap(j, j - 1)
end
end
arr
end
Easy implementation of Insertion sort in ruby.
def insertion(arr)
for i in (1...(arr.size))
if arr[i-1] > arr[i]
i.downto(1) do |el|
if arr[el] < arr[el-1]
arr[el-1], arr[el] = arr[el], arr[el-1]
end
end
end
end
arr
end
arr = %w(3 7 4 9 5 2 6 1 0)
p insertion(arr)

Maximum and minimum value in an Array

I wrote a Ruby code to get max and min values from an array. The code prints the max value (8) correct but it's not printing the minimum value (2). Please let me know what went wrong in my code.
class MaxMinArray
def MaxMinMethod()
array = [4,2,8,3,5]
maxNo = array[0]
minNo = array[0]
arrayLength = array.length
for i in 1..arrayLength
if array[i].to_i > maxNo
maxNo = array[i]
end
if array[i].to_i < minNo
minNo = array[i]
end
end
puts "Maximum no. in the given array: " + maxNo.to_s
puts "Minimum no. in the given array: " + minNo.to_s
end
end
MaxiMinArrayObj = MaxMinArray.new
MaxiMinArrayObj.MaxMinMethod()
It is the combination of two things.
First, you iterated over for i in 1..arrayLength, which iterates past the last element in array. After the last element, array[i] is nil.
Second, you have the condition if array[i].to_i < minNo, which can be satisfied even if array[i] is not a number.
Because of that, the nil returned by array[i] after the last element satisfies the condition due to nil.to_i being 0, and that nil is assigned to minNo.
I realize you're trying to learn how to code, but, as you do so, it's also important to learn to take advantage of pre-existing solutions. Reinventing wheels will waste your time debugging code.
I'd write the code like:
def max_min(ary)
[ary.max, ary.min]
end
max_min([1,2,4]) # => [4, 1]
But, then again, Ruby already has a good minmax method:
[1,2,4].minmax # => [1, 4]
so use it and focus your energy on more interesting things.
If you have to see the values in the opposite order, use:
[1,2,4].minmax.reverse # => [4, 1]
A more verbose/old-school way of doing it is:
FIXNUM_MAX = (2 ** (0.size * 8 - 2) - 1)
FIXNUM_MIN = -(2 ** (0.size * 8 - 2))
def max_min(ary)
return [nil, nil] if ary.empty?
minval = FIXNUM_MAX
maxval = FIXNUM_MIN
ary.each do |i|
minval = i if i < minval
maxval = i if i > maxval
end
[maxval, minval]
end
max_min([1,2,4]) # => [4, 1]
[1,2,4].minmax.reverse # => [4, 1]
That simply loops over the array, checks each value to see if it's either smaller or larger than the last minimum or maximum value, and, if so, remembers it. Once the array is exhausted the values are returned. It's a lot more concise because using each removes a lot of the hassle of trying to walk the array using index values. We almost never use for in Ruby, especially to walk through an array.
(Technically Ruby can hold values well beyond 4611686018427387903 and -4611686018427387904, which are what FIXNUM_MAX and FIXNUM_MIN are, but those suffice for most things we want to do.)
It's not a good practice to print inside methods as long as you might want to use the results for something else.
Also Ruby comes with all sorts of magic methods to get the maximum and minimum of an array:
results = [5, 23, 43, 2, 3, 0].minmax
puts "Maximum no. in the given array: " + results[1]
puts "Minimum no. in the given array: " + results[0]
You should iterate from 1 to arrayLength - 1 (it's an index of the last element). You can use three dots for this:
for i in 1...arrayLength
If I were not allowed to used Ruby's minmax method, than I would do it probably like this:
array = [4,2,8,3,5]
min, max = nil, nil
array.each do |element|
min = element if min.nil? || element < min
max = element if max.nil? || max < element
end
puts [min, max]
# => [2, 8]
I used this expression for the min and max within ruby, it's a stretch but it works
class RubyMinMax
def self.min_function(array=[])
puts "my array is the following #{array}"
puts "the length of the array is #{array.length}"
it = 0
while array.length > 1
array.fetch(it).to_i > array.fetch(it-1).to_i ? array.delete_at(it) : array.delete_at(it-1)
it = array.length-1
end
print array[0]
end
def self.max_function(array=[])
puts "my array is the following #{array}"
puts "the length of the array is #{array.length}"
it = 0
while array.length > 1
array.fetch(it).to_i < array.fetch(it-1).to_i ? array.delete_at(it) : array.delete_at(it-1)
it = array.length-1
end
print array[0]
end
end
RubyMinMax.min_function([18, 19, 17])
RubyMinMax.max_function([18, 19, 17])
In the simplest way you can use max and min method of array.
:001 > [1,4,1,3,4,5].max
=> 5
:002 > [1,4,1,3,4,5].min
=> 1
And if your array may contain nil the first compact it the use min max
For example
:003 > [1,4,1,3,4,5,nil].compact
=> [1, 4, 1, 3, 4, 5]
:004 > [1,4,1,3,4,5].max
=> 5
:005 > [1,4,1,3,4,5].min
=> 1

Setting optional method arguments?

I am trying to define a method to sum the elements of a given array. So far I have:
def sum2
return self if self.length <=1
i = self.length
#sum2 = sum2(i-1) + self[i]
end
I'm getting an invalid argument error for the second call of sum2(i-1). Is there any way I can set it to take either 0 or 1 arguments? Or, am I going about this the wrong way?
It's not totally clear from the question phrasing, but I assume sum2 is a method in an array class that you've defined yourself. So, I assume it's derived from a Ruby Array class.
Currently, your method returns the array self if it has no more than one element. Technically, the array of one element isn't the sum of elements. So you don't want to return self in that case.
But you can use Ruby's array methods to simplify:
def sum2
self.inject(:+)
end
This will return nil if the array has zero length, and the sum of elements otherwise. If you want to return 0 on a length 0 array, then:
def sum2
return (self.length == 0) ? 0 : self.inject(:+)
end
Or more simply, per #toro2k's comment:
def sum2
self.inject(0, :+)
end

How to count in a loop?

I'm new to Ruby, how can I count elements in a loop?
In Java I would write it like this
int[] tablica = { 23,53,23,13 };
int sum = 0;
for (int i = 0; i <= 1; i++) { // **only first two**
sum += tablica[i];
}
System.out.println(sum);
EDIT: I want only first two
You can sum all the elements in an array like this:
arr = [1,2,3,4,5,6]
arr.inject(:+)
# any operator can be here, it will be
# interpolated between the elements (if you use - for example
# you will get 1-2-3-4-5-6)
Or, if you want to iterate over the elements:
arr.each do |element|
do_something_with(element)
Or, if you need the index too:
arr.each_with_index do |element, index|
puts "#{index}: #{element}"
tablica.take(2).reduce(:+)
But seriously? What's wrong with just
tablica[0] + tablica[1]
Hey, it even works in Ruby and Java … and C, C++, Objective-C, Objective-C++, D, C#, ECMAScript, PHP, Python. Without changes.
There are many ways, but if you want the current object and a counter use the each_with_index method
some_collection.each_with_index do |o, i|
# 'o' is your object, 'i' is your index
end
EDIT: Oops, read that too quickly. You can do this
sum = 0
some_collection.each { |i| sum += i }
With Enumerable#inject:
tablica = [23, 53, 23, 13]
tablica.inject(0, :+) # 112
If you just need a sum, here is a simple way:
tablica = [ 23,53,23,13 ]
puts tablica.inject(0){|sum,current_number| sum+current_number}
For first two elements (or whatever contiguous range) you can use a range:
tablica = [ 23,53,23,13 ]
puts tablica[0..1].inject(0){|sum,current_number| sum+current_number}
What this does:
The block (the statement within {...}) is called internally by inject, once for each element in the array.
At the first iteration, sum has the initial value 0 (that we passed to inject)
And current_number contains the 0th element in the array.
We add the two values (0 and 23) and this value gets assigned to sum when the block returns.
Then on the next iteration, we get sum variable as 23 and current_number as 53. And the process repeats.

More ruby-like solution to this problem?

I am learning ruby and practicing it by solving problems from Project Euler.
This is my solution for problem 12.
# Project Euler problem: 12
# What is the value of the first triangle number to have over five hundred divisors?
require 'prime'
triangle_number = ->(num){ (num *(num + 1)) / 2 }
factor_count = ->(num) do
prime_fac = Prime.prime_division(num)
exponents = prime_fac.collect { |item| item.last + 1 }
fac_count = exponents.inject(:*)
end
n = 2
loop do
tn = triangle_number.(n)
if factor_count.(tn) >= 500
puts tn
break
end
n += 1
end
Any improvements that can be made to this piece of code?
As others have stated, Rubyists will use methods or blocks way more than lambdas.
Ruby's Enumerable is a very powerful mixin, so I feel it pays here to build an enumerable in a similar way as Prime. So:
require 'prime'
class Triangular
class << self
include Enumerable
def each
sum = 0
1.upto(Float::INFINITY) do |i|
yield sum += i
end
end
end
end
This is very versatile. Just checking it works:
Triangular.first(4) # => [1, 3, 7, 10]
Good. Now you can use it to solve your problem:
def factor_count(num)
prime_fac = Prime.prime_division(num)
exponents = prime_fac.collect { |item| item.last + 1 }
exponents.inject(1, :*)
end
Triangular.find{|t| factor_count(t) >= 500} # => 76576500
Notes:
Float::INFINITY is new to 1.9.2. Either use 1.0/0, require 'backports' or do a loop if using an earlier version.
The each could be improved by first checking that a block is passed; you'll often see things like:
def each
return to_enum __method__ unless block_given?
# ...
Rather than solve the problem in one go, looking at the individual parts of the problem might help you understand ruby a bit better.
The first part is finding out what the triangle number would be. Since this uses sequence of natural numbers, you can represent this using a range in ruby. Here's an example:
(1..10).to_a => [1,2,3,4,5,6,7,8,9,10]
An array in ruby is considered an enumerable, and ruby provides lots of ways to enumerate over data. Using this notion you can iterate over this array using the each method and pass a block that sums the numbers.
sum = 0
(1..10).each do |x|
sum += x
end
sum => 55
This can also be done using another enumerable method known as inject that will pass what is returned from the previous element to the current element. Using this, you can get the sum in one line. In this example I use 1.upto(10), which will functionally work the same as (1..10).
1.upto(10).inject(0) {|sum, x| sum + x} => 55
Stepping through this, the first time this is called, sum = 0, x = 1, so (sum + x) = 1. Then it passes this to the next element and so sum = 1, x = 2, (sum + x) = 3. Next sum = 3, x = 3, (sum + x) = 6. sum = 6, x = 4, (sum + x) = 10. Etc etc.
That's just the first step of this problem. If you want to learn the language in this way, you should approach each part of the problem and learn what is appropriate to learn for that part, rather than tackling the entire problem.
REFACTORED SOLUTION (though not efficient at all)
def factors(n)
(1..n).select{|x| n % x == 0}
end
def triangle(n)
(n * (n + 1)) / 2
end
n = 2
until factors(triangle(n)).size >= 500
puts n
n += 1
end
puts triangle(n)
It looks like you are coming from writing Ocaml, or another functional language. In Ruby, you would want to use more def to define your methods. Ruby is about staying clean. But that might also be a personal preference.
And rather than a loop do you could while (faction_count(traingle_number(n)) < 500) do but for some that might be too much for one line.

Resources