How to find max in Ruby without using "max" function - arrays

I need to find the max value of an array without using the max method. Right now I have:
def max(arr)
largest_num = arr(1)
arr.each do |num|
if element >= largest_num
largest_num = num
else
largest_num = largest_num
end
puts largest_num
end
my_numbers = [20, 30, 40, 50]
puts max(my_numbers)
end

Why don't you just use sort and last?
array = [3,7,2,4,6,1,8,5]
array.sort.last
#=> 8

i was told i should use .sort and .last but not quite sure where to even start
It's really important to be a self-starter when programming. It's an essential characteristic, because the field and all technologies are moving quickly. I'd suggest reading "How much research effort is expected of Stack Overflow users?" also, especially if you want to use Stack Overflow as a resource.
Here's how to learn to experiment with Ruby and to teach yourself:
Ruby has IRB bundled with it. Type irb at the command-line and it should open and present you with a prompt. At that prompt you can enter Ruby expressions and see the result. My prompt is probably not the same as yours because mine is customized, but you can figure out how to work with that:
$ irb
irb(main):001:0>
To assign an array to a variable:
irb(main):001:0> my_numbers = [20, 30, 40, 50]
=> [20, 30, 40, 50]
I can look at the value assigned to my_numbers by entering the name of the variable and pressing Return or Enter:
irb(main):002:0> my_numbers
=> [20, 30, 40, 50]
I can experiment using methods on my_numbers:
irb(main):003:0> my_numbers.shuffle
=> [50, 30, 40, 20]
That took the array and randomized it. It didn't change my_numbers, it only shuffled the array and output a new array in the shuffled order:
irb(main):004:0> my_numbers
=> [20, 30, 40, 50]
Each time shuffle is run it randomizes the array and returns another array:
irb(main):005:0> my_numbers.shuffle
=> [50, 20, 30, 40]
irb(main):006:0> my_numbers.shuffle
=> [40, 20, 30, 50]
Since you want to use sort and last to find the maximum value, it'd be good to start with an out-of-order array. Testing sort:
irb(main):009:0> my_numbers.shuffle.sort
=> [20, 30, 40, 50]
The array is sorted after shuffling.
Here's what last does:
irb(main):010:0> my_numbers.last
=> 50
Now you know enough to figure it out for yourself.

If you are required to use sort and last, then the answer below will not work for you.
arr.sort.last is inefficient, since it requires sorting the whole array when all you need is the biggest. Try something like:
arr.reduce{|largest, num| if num > largest then num else largest end}
The reduce function (also aliased as inject) is used to "reduce" an array down to a single object. To implement a sum, you could do something like:
num_arr = [1,2,3,4,5]
num_arr.reduce(0){|sum, num| sum + num} #=> 15
0 is the starting value of the sum, and then for each element the block is run with the sum so far and the element in the array. Then the result of the block (sum + num is returned since in ruby the last statement is implicitly returned) is set as the new value of sum for the next element. The final value of sum is what is returned.
This is similar to doing:
sum = 0
sum = sum + num_arr[0]
sum = sum + num_arr[1]
sum = sum + num_arr[2]
sum = sum + num_arr[3]
sum = sum + num_arr[4]
If you don't specify a starting value, then the first element is taken as the starting value. So, in my reduce solution, the first element is set as the "largest", and then for each element in turn the largest is either passed on or if the element is bigger than the current largest, it becomes the new largest.

If you were really told that you should use sort and last then the answer is quite simple:
2.1.1 :003 > [2,3,1,4,8,6].sort.last
=> 8
If you want it in method:
def max(arr); arr.sort.last; end
2.1.1 :004 > def max(arr); arr.sort.last; end
=> :max
2.1.1 :005 > max([2,1,3])
=> 3

First sort the array without using the sort method if you are trying to solve this without the default function
asc = [45,34,12,4,5,32,54,76]
asc.each do |a|
i = 0
asc.each do |b|
if b > asc[i +1]
asc[i], asc[i + 1] = asc[i + 1], asc[i]
end
i += 1 if i < asc.size - 2
end
end
p asc.last
This will give the largest number from the sorted array

Related

How to find out if an arithmetic sequence exists in an array

If there is an array that contains random integers in ascending order, how can I tell if this array contains a arithmetic sequence (length>3) with the common differece x?
Example:
Input: Array=[1,2,4,5,8,10,17,19,20,23,30,36,40,50]
x=10
Output: True
Explanation of the Example: the array contains [10,20,30,40,50], which is a arithmetic sequence (length=5) with the common differece 10.
Thanks!
I apologize that I have not try any code to solve this since I have no clue yet.
After reading the answers, I tried it in python.
Here are my codes:
df = [1,10,11,20,21,30,40]
i=0
common_differene=10
df_len=len(df)
for position_1 in range(df_len):
for position_2 in range(df_len):
if df[position_1] + common_differene == df[position_2]:
position_1=position_2
i=i+1
print(i)
However, it returns 9 instead of 4.
Is there anyway to prevent the repetitive counting in one sequence [10,20,30,40] and also prevent accumulating i from other sequences [1,11,21]?
You can solve your problem by using 2 loops, one to run through every element and the other one to check if the element is currentElement+x, if you find one that does, you can continue form there.
With the added rule of the sequence being more than 2 elements long, I have recreated your problem in FREE BASIC:
DIM array(13) As Integer = {1, 2, 4, 5, 8, 10, 17, 19, 20, 23, 30, 36, 40, 50}
DIM x as Integer = 10
DIM arithmeticArrayMinLength as Integer = 3
DIM index as Integer = 0
FOR position As Integer = LBound(array) To UBound(array)
FOR position2 As Integer = LBound(array) To UBound(array)
IF (array(position) + x = array(position2)) THEN
position = position2
index = index + 1
END IF
NEXT
NEXT
IF (index <= arithmeticArrayMinLength) THEN
PRINT false
ELSE
PRINT true
END IF
Hope it helps
Edit:
After reviewing your edit, I have come up with a solution in Python that returns all arithmetic sequences, keeping the order of the list:
def arithmeticSequence(A,n):
SubSequence=[]
ArithmeticSequences=[]
#Create array of pairs from array A
for index,item in enumerate(A[:-1]):
for index2,item2 in enumerate(A[index+1:]):
SubSequence.append([item,item2])
#finding arithmetic sequences
for index,pair in enumerate(SubSequence):
if (pair[1] - pair[0] == n):
found = [pair[0],pair[1]]
for index2,pair2 in enumerate(SubSequence[index+1:]):
if (pair2[0]==found[-1] and pair2[1]-pair2[0]==n):
found.append(pair2[1])
if (len(found)>2): ArithmeticSequences.append(found)
return ArithmeticSequences
df = [1,10,11,20,21,30,40]
common_differene=10
arseq=arithmeticSequence(df,common_differene)
print(arseq)
Output: [[1, 11, 21], [10, 20, 30, 40], [20, 30, 40]]
This is how you can get all the arithmetic sequences out of df for you to do whatever you want with them.
Now, if you want to remove the sub-sequences of already existing arithmetic sequences, you can try running it through:
def distinct(A):
DistinctArithmeticSequences = A
for index,item in enumerate(A):
for index2,item2 in enumerate([x for x in A if x != item]):
if (set(item2) <= set(item)):
DistinctArithmeticSequences.remove(item2)
return DistinctArithmeticSequences
darseq=distinct(arseq)
print(darseq)
Output: [[1, 11, 21], [10, 20, 30, 40]]
Note: Not gonna lie, this was fun figuring out!
Try from 1: check the presence of 11, 21, 31... (you can stop immediately)
Try from 2: check the presence of 12, 22, 32... (you can stop immediately)
Try from 4: check the presence of 14, 24, 34... (you can stop immediately)
...
Try from 10: check the presence of 20, 30, 40... (bingo !)
You can use linear searches, but for a large array, a hash map will be better. If you can stop as soon as you have found a sequence of length > 3, this procedure takes linear time.
Scan the list increasingly and for every element v, check if the element v + 10 is present and draw a link between them. This search can be done in linear time as a modified merge operation.
E.g. from 1, search 11; you can stop at 17; from 2, search 12; you can stop at 17; ... ; from 8, search 18; you can stop at 19...
Now you have a graph, the connected components of which form arithmetic sequences. You can traverse the array in search of a long sequence (or a longest), also in linear time.
In the given example, the only links are 10->-20->-30->-40->-50.

Ruby: How to remove specific digits from integers that are inside an array?

I'm new to programming. I would like to take an array of Integers, like [155, 151, 2, 15] and remove a specific digit, in this case 5, and add up the new numbers. I've broken this problem up into smaller steps, and gotten the result I wanted. I'm just wondering if there are easier ways to do a problem like this? Maybe a different method I could use? Any help is greatly appreciated.
Here is the code I have:
arr = [155, 151, 2, 15]
# goal: remove the 5 digit from values and add
# new numbers together --> 1 + 11 + 2 + 1 == 15
# convert to arr of strings and delete zeros
str_arr = []
arr.each do |el|
str_arr << el.to_s.delete('5')
end
# convert to arr of nums
num_arr = []
str_arr.each do |el|
num_arr << el.to_i
end
# reduce num_arr
num_arr.reduce(:+)
Maybe you can use map instead each, this way you avoid having to push to a new initialized array each element transformed inside the block, like:
p [155, 151, 2, 15].map { |el| el.to_s.delete('5').to_i }.reduce(:+)
# 15
If using ruby 2.4 or higher you can use Enumerable#sum instead reduce (which seems to be a faster option).
p [155, 151, 2, 15].sum { |el| el.to_s.delete('5').to_i }
# 15
arr = [155, 151, 2, 15]
arr.sum { |n| (n.digits - [5]).reverse.join.to_i }
#=> 15
using eval:
eval(arr.join('+').delete('5'))
#=> 15
using inject:
arr.inject(0){|sum, element| element.to_s.delete('5').to_i + sum }
#=> 15
The solution using eval is more fun, but the solution using inject is arguably easier to understand. Cheers.

Using memoization for storing values in ruby array

For a short array the following function works well. It's supposed to return the first array pair that whe sum is equal to a given integer. However, if the array has a length upwards of 10 million elements, the request times out, because (I think) is storing thousands of values in the variable I create in the first line. I know I have to use memoization (||=) but have no idea how to use it.
array1 = [1,2,3,4,5,6,7]
number = 3
array2 = [1,2,3.....n] # millions of elements
combos = array1.combination(2).to_a
(combos.select { |x,y| x + y == number }).sort.first
I need to gather all possible pairs to sort them, I'm using select to go through the entire list and not stop at the first pair that returns true.
This is one of the possible solutions.
def sum_pairs(ints, s)
seen = {}
for i in ints do
return [s-i, i] if seen[s-i]
seen[i] = true
end
nil
end
def find_smallest(arr, nbr)
first, *rest = arr.sort
until rest.empty?
matching = rest.bsearch { |n| n == nbr - first }
return [first, matching] unless matching.nil?
first, *rest = rest
end
nil
end
arr = [12, 7, 4, 5, 14, 9]
find_smallest(arr, 19) #=> [5, 14]
find_smallest(arr, 20) #=> nil
I've used the method Array#bsearch (rather than Enumerable#find to speed up the search for an element equal to nbr - first (O(log rest.size) vs. O(rest.size)).

You have an array of integers, and for each index you want to find the product of every integer except the integer at that index

I was going over some interview questions and came across this one at a website. I have come up with a solution in Ruby, and I wish to know if it is efficient and an acceptable solution. I have been coding for a while now, but never concentrated on complexity of a solution before. Now I am trying to learn to minimize the time and space complexity.
Question:
You have an array of integers, and for each index you want to find the product of every integer except the integer at that index.
Example:
arr = [1,2,4,5]
result = [40, 20, 10, 8]
# result = [2*4*5, 1*4*5, 1*2*5, 1*2*4]
With that in mind, I came up with this solution.
Solution:
def find_products(input_array)
product_array = []
input_array.length.times do |iteration|
a = input_array.shift
product_array << input_array.inject(:*)
input_array << a
end
product_array
end
arr = find_products([1,7,98,4])
From what I understand, I am accessing the array as many times as its length, which is considered to be terrible in terms of efficiency and speed. I am still unsure on what is the complexity of my solution.
Any help in making it more efficient is appreciated and if you can also tell the complexity of my solution and how to calculate that, it will be even better.
Thanks
def product_of_others(arr)
case arr.count(0)
when 0
total = arr.reduce(1,:*)
arr.map { |n| total/n }
when 1
ndx_of_0 = arr.index(0)
arr.map.with_index do |n,i|
if i==ndx_of_0
arr[0,ndx_of_0].reduce(1,:*) * arr[ndx_of_0+1..-1].reduce(1,:*)
else
0
end
end
else
arr.map { 0 }
end
end
product_of_others [1,2,4,5] #=> [40, 20, 10, 8]
product_of_others [1,-2,0,5] #=> [0, 0, -10, 0]
product_of_others [0,-2,4,5] #=> [-40, 0, 0, 0]
product_of_others [1,-2,4,0] #=> [0, 0, 0, -8]
product_of_others [1,0,4,0] #=> [0, 0, 0, 0]
product_of_others [] #=> []
For the case where arr contains no zeroes I used arr.reduce(1,:*) rather than arr.reduce(:*) in case the array is empty. Similarly, if arr contains one zero, I used .reduce(1,:*) in case the zero was at the beginning or end of the array.
For inputs not containing zeros (for others, see below)
Easiest (and relatively efficient) to me seems to first get the total product:
total_product = array.inject(1){|product, number| product * number}
And then map each array element to the total_product divided by the element:
result = array.map {|number| total_product / number}
After initial calculation of total_product = 1*2*4*5 this will calculate
result = [40/1, 40/2, 40/4, 40/5]
As far as I remember this sums up to O(n) [creating total product: touch each number once] + O(n) [creating one result per number: touch each number once]. (correct me if i am wrong)
Update
As #hirolau and #CarySwoveland pointed out, there is a problem if you have (exactly 1) 0 in the input, thus:
For inputs containing zeros (workaroundish, but borrows performance benefit and complexity class)
zero_count = array.count{|number| number == 0}
if zero_count == 0
# as before
elsif zero_count == 1
# one zero in input, result will only have 1 non-zero
nonzero_array = array.reject{|n| n == 0}
total_product = nonzero_array.inject(1){|product, number| product * number}
result = array.map do |number|
(number == 0) ? total_product : 0
end
else
# more than one zero? All products will be zero!
result = array.map{|_| 0}
end
Sorry that this answer by now basically equals #CarySwoveland, but I think my code is more explicit.
Look at the comments about further performance considerations.
Here is how I would do it:
arr = [1,2,4,5]
result = arr.map do |x|
new_array = arr.dup # Create a copy of original array
new_array.delete_at(arr.index(x)) # Remove an instance of the current value
new_array.inject(:*) # Return the product.
end
p result # => [40, 20, 10, 8]
I not know ruby, but, accessing an array is O(1), that means that is in constant time, so the complexity of your algorithm is O(n), it is very good. I don't think that a better solution can be found in terms of complexity. The real speed is another issue, but that solution is fine

Cut a set of ranges of integers from another set of ranges

I have two arrays of ranges in this form:
wanted = {[10, 15], [20, 25]}
cut = {[5, 12], [22, 24]}
So wanted is an array of two elements (ranges) - [10, 15] and [20, 25].
Each of the two arrays fulfil these conditions:
It is sorted by the first value in each range of integers
The ranges will never overlap (e.g. [10, 15], [15, 25] is not possible)
This also means that each range is unique within the array (no [1, 5], [1, 5])
If a range is just one integer wide, it will be displayed as [5, 5] (beginning and end are equal)
I now want to obtain an array of ranges, where all ranges from cut have been removed from the ranges in wanted.
result = {[13, 15], [20, 21], [25, 25]}
Is there some brilliant algorithm better / easier / faster than the below?
For each element in wanted, compare that element to one element after another from cut until the element from cut ends above the element from wanted.
Say there are n elements in wanted and m elements in cut.
The following is an O(m + n) algorithm to perform the required task:
j = 1
result = {}
for i = 1:n
// go to next cut while current cut ends before current item
while j <= m && cut[j].end < wanted[i].start
j++
// cut after item, thus no overlap
if j > m || cut[j].start > wanted[i].end
result += (wanted[i].start, wanted[i].end)
else // overlap
// extract from start to cut start
if cut[j].start > wanted[i].start
result += (wanted[i].start, cut[j].start-1)
// extract from cut end to end
if cut[j].end < wanted[i].end
result += (cut[j].end+1, wanted[i].end)
j++
Note that, asymptotically, you can't do better than O(m + n), since it should be reasonably easy to prove that you need to look at every element (in the worst case).
What is the biggest size which wanted and cut may be? Comparing the "first element from wanted" with "all from cut" will take O(n^2) run time, i.e. very slow if the arrays are large.
It would be much faster to work over each array in parallel until you reach the end of both, something like a "merge".

Resources