How to write my own max function - ruby

I know that there is a max function from the Enumerable library in Ruby.
However, I'm trying to figure out how to write my own max method in which the largest number in an array is figured out.
How do I do that? I'm really at loss because when I Google it, all I keep getting is the max function itself.
Any help/advice would be helpful!

Another naive approach is -
list = [3,4,2,5,6,7,8,2,5,1,4,4,6]
def maximum(list)
len = list.size - 1
maximum = list[0]
for i in 1..len
if maximum < list[i]
maximum = list[i]
end
end
maximum
end
puts maximum(list)
# >> 8
Here is the graphical explanation(taken from this link) -

You have 2 approaches: Enumerable#each (imperative) or Enumerable#reduce (usually functional, depends on how you use it). I prefer functional solutions, so I'd write:
module Enumerable
def my_max
reduce { |current_max, x| x > current_max ? x : current_max }
end
end

Related

How could I DRY this while loop?

I need to DRY this code but I don't know how.
I tried to dry the if condition but I don't know how to put the while in this.
def sum_with_while(min, max)
# CONSTRAINT: you should use a while..end structure
array = (min..max).to_a
sum = 0
count = 0
if min > max
return -1
else
while count < array.length
sum += array[count]
count += 1
end
end
return sum
end
Welcome to stack overflow!
Firstly, I should point out that "DRY" stands for "Don't Repeat Yourself". Since there's no repetition here, that's not really the problem with this code.
The biggest issue here is it's unrubyish. The ruby community has certain things it approves of, and certain things it avoids. That said, while loops are themselves considered bad ruby, so if you've been told to write it with a while loop, I'm guessing you're trying to get us to do your homework for you.
So I'm going to give you a couple of things to do a web search for that will help start you off:
ruby guard clauses - this will reduce your if-else-end into a simple if
ruby array pop - you can do while item = array.pop - since pop returns nil once the array is empty, you don't need a count. Again, bad ruby to do this... but maybe consider while array.any?
ruby implicit method return - generally we avoid commands we don't need
It's worth noting that using the techniques above, you can get the content of the method down to 7 reasonably readable lines. If you're allowed to use .inject or .sum instead of while, this whole method becomes 2 lines.
(as HP_hovercraft points out, the ternary operator reduces this down to 1 line. On production code, I'd be tempted to leave it as 2 lines for readability - but that's just personal preference)
You can put the whole thing in one line with a ternary:
def sum_with_while(min, max)
min > max ? -1 : [*(min..max)].inject(0){|sum,x| sum + x }
end
This is one option, cleaning up your code, see comments:
def sum_with_while(range) # pass a range
array = range.to_a
sum, count = 0, 0 # parallel assignment
while count < array.length
sum += array[count]
count += 1
end
sum # no need to return
end
sum_with_while(10..20)
#=> 165
More Rubyish:
(min..max).sum
Rule 1: Choose the right algorithm.
You wish to compute an arithmetic series.1
def sum_with_while(min, max)
max >= min ? (max-min+1)*(min+max)/2 : -1
end
sum_with_while(4, 4)
#=> 4
sum_with_while(4, 6)
#=> 15
sum_with_while(101, 9999999999999)
#=> 49999999999994999999994950
1. An arithmetic series is the sum of the elements of an arithmetic sequence. Each term of the latter is computed from the previous one by adding a fixed constant n (possibly negative). Heremax-min+1 is the number of terms in the sequence and (min+max)/2, if (min+max) is even, is the average of the values in the sequence. As (max-min+1)*(min+max) is even, this works when (min+max) is odd as well.

How to create a method that returns the nth prime number?

I'm trying to write a method that returns the nth prime number.
I've worked out a solution but the problem is in my method. I create a large array of numbers that seems to process super slow. (1..104729).to_a to be exact. I chose 104729 because the max n can be is 10000 and the 10000th integer is 104729. I'm looking for a way to optimize my method.
Is 104729 is too large a value? Is there a way to write this so that I'm not creating a large array?
Here's the method:
def PrimeMover(num)
def is_prime(x)
i = 0
nums = (2..x).to_a
while nums[i] < nums.max
if x % nums[i] != 0
i += 1
else
return false
end
end
return true
end
primes_arr = (3..104729).to_a.select {|y| is_prime(y)}
primes_arr[num]
end
require "prime"
def find_prime(nth)
Prime.take(nth).last
end
Combine Ruby's built-in prime library, and a lazy enumerator for performance:
require 'prime'
(1...100_000).lazy.select(&:prime?).take(100).to_a
Or simply, as highlighted by Arturo:
Prime.take(100)
You can use Ruby's built in #prime? method, which seems pretty efficient.
The code:
require 'prime'
primes_arr = (3..104729).to_a.select &:prime?
runs in 2-3 seconds on my machine, which I find somewhat acceptable.
If you need even better performance or if you really need to write your own method, try implementing the Sieve of Erathostenes. Here are some Ruby samples of that: http://rosettacode.org/wiki/Sieve_of_Eratosthenes#Ruby
Here's an optimal a trial division implementation of is_prime without relying on the Prime class:
A prime number is a whole number divisible only by 1 and itself, and 1 is not prime. So we want to know if x divides into anything less than x and greater than 1. So we start the count at 2, and we end at x - 1.
def prime?(x)
return false if x < 2
2.upto(x - 1) do |n|
return false if (x % n).zero?
end
true
end
As soon as x % n has a remainder, we can break the loop and say this number is not prime. This saves you from looping over the entire range. If all the possible numbers were exhausted, we know the number is prime.
This is still not optimal. For that you would need a sieve, or a different detection algorithm to trial division. But it's a big improvement on your code. Taking the nth up to you.

Error accessing an array's value by it's index?

Trying to sum up all the numbers in an array. Example 10 + 20 + 30 should be 60.
def sum *arr
i=0
total=0
while i <= arr.count
total += arr[i]
i+=1
end
total
end
puts sum(10,20,30)
Why am I getting this error. This code looks like it should work to me. What am I doing wrong? Why wont it let me access the array value by it's index?
p8.rb:23:in `+': nil can't be coerced into Fixnum (TypeError)
from p8.rb:23:in `sum'
from p8.rb:29:in `<main>'
Change
while i <= arr.count
to
while i < arr.count
arr[arr.count] is always out of bounds.
Fyi a shorter way to write sum is:
def sum *arr
arr.inject(:+)
end
Matt's answer gives you the canonical Ruby way to sum, using inject. But if you're not ready to learn inject, at least save yourself the trouble of manually keeping track of array indexes (where your actual problem lies!) by using #each to iterate through the array like so:
def sum *arr
total = 0
arr.each do |x|
total += x
end
total
end
puts sum(10,20,30) # => 60
Matt's answer is both slick and correct, but you hit the error because ruby zero indexes arrays. So if you changed the count condition
while i <= arr.count - 1
your error would go away

I need help on understading: Write a method, sum which takes an array of numbers and returns the sum of the numbers

I've been studying ruby and have been taking some exercises to see how much I have learned and I've come across this:
Q: Write a method, sum which takes an array of numbers and returns the sum of the numbers.
The answer was provided for the problem but I don't understand why or how. I would like some help from anyone to explain them for me in simple terms so that I can understand this. Please keep in mind that I'm new to programming. Thank you.
A:
def sum(nums)
total = 0
i = 0
while i < nums.count
total += nums[i]
i += 1
end
# return total
total
end
Let me add some comments to see if this helps...
def sum(nums)
# initialize total to zero
total = 0
# initialize a counter to zero
i = 0
# while the counter is less than the size / count of the array...
while i < nums.count
# add the number at the array index of i to total
# this can also be written: total = total + nums[i]
total += nums[i]
# increment your counter, then loop
i += 1
end
# return total
total
end
The way to do this with ruby is
def sum (nums_array)
nums_array.inject(:+)
end
Equivalently, you could use reduce, which is an alias for inject.
Inject iterates over your array cumulatively applying any binary operation to every element, returning the accumulator (in this case, the sum of all the elements). You could also do something like
nums_array.inject(:-)
nums_array.inject(:*)
nums_array.inject(:%)
and etc.
The best place to test any Ruby method is in IRB or PRY on the command line, or, if you'd rather use something with a GUI and are working on a Mac, CodeRunner is great.
For more on inject / reduce (or any method you come across), the ruby docs are a great resource.
def sum(nums)
total = 0
i = 0 # i is set to `0`, as in Ruby array is 0 based.i will point to the
# first element in the array initially.
while i < nums.count # loop to iterate through the array till the last index come.
total += nums[i] # nums[i] is for accessing the element from the array at index i.
# and adding the value of total in previous iteration to current element
# of the array at i(or to the initial value of total,if it is the first iteration).
i += 1 # this move the i from current index to next index of the array.
end
# return total
total
end
i += 1 is called the syntactic sugar of i=i+1.Same is true for total += nums[i].
This is horrible. Whoever wrote doesn't understand the first thing about Ruby. He doesn't even understand much of programming, apparently. Just forget about it.
This is how a Rubyist or pretty much any other programmer would solve that problem:
def sum(nums)
nums.inject(0, :+)
end
Unlike the code that was provided to you, this doesn't use any concepts outside of some basic math. (Fold and Addition.)

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