Related
It's my very 1st time doing algorithm.
Can someone help me solve the 2 followings?:
A <- [3, 3, 0]
While A[2] < A[1] :
A[0] <- A[0] + A[0]
A[2] <- A[2] + 1
Show A[0] + A[2]
And
> A <- 4
B <- 7
If B < 5 :
Show A - B
Else :
Show 2*B
Thanks!
It seems like homework, instead of giving the exact solution, I will give you some clues:
A <- 4: Find out what it means, probably A will get assigned the value of 4.
B <- 7: Similar for above.
The IF statement compares the two values, find out which is true, if true, the line Show A - B is executed, ELSE (thus if the condition in the IF is false), the second statement (Show 2*B) is executed.
For the while loop, make a table with A[0], A[1] and A[2], and every time the value changes, write the new value in the column (so keep track of the values of A[0] to A[2]). A While loop continues while the condition is true. When the condition is false, the statement continues after the While (thus Show A[0] + A[2].
This question was asked somewhere else, but I just wanted to check if what I did was applicable given the rspec circumstances:
Write a method that takes two sorted arrays and produces the sorted array that combines both.
Restrictions:
Do not call sort anywhere.
Do not in any way modify the two arrays given to you.
Do not circumvent (2) by cloning or duplicating the two arrays, only to modify the copies.
Hint: you will probably need indices into the two arrays.
combine_arrays([1, 3, 5], [2, 4, 6]) == [1, 2, 3, 4, 5, 6]
Can you just combine the two arrays into a single array and then run a typical bubble sort?
def combine_arrays(arr1,arr2)
final = arr1 + arr2
sorted = true
while sorted do
sorted = false
(0..final.length - 2).each do |x|
if final[x] > final[x+1]
final[x], final[x+1] = final[x+1], final[x]
sorted = true
end
end
end
final
end
p combine_arrays([1,3,5],[2,4,6]) => [1, 2, 3, 4, 5, 6]
Here is a variant which relies solely on Ruby's enumerators. The result is short and sweet.
# merge two sorted arrays into a sorted combined array
def merge(a1, a2)
[].tap do |combined|
e1, e2 = a1.each, a2.each
# The following three loops terminate appropriately because
# StopIteration acts as a break for Kernel#loop.
# First, keep appending smaller element until one of
# the enumerators run out of data
loop { combined << (e1.peek <= e2.peek ? e1 : e2).next }
# At this point, one of these enumerators is "empty" and will
# break immediately. The other appends all remaining data.
loop { combined << e1.next }
loop { combined << e2.next }
end
end
The first loop keeps grabbing the minimum of the two enumerator values until one of the enumerators runs out of values. The second loop then appends all remaining (which may be none) values from the first array's enumerator, the third loop does the same for the second array's enumerator, and tap hands back the resulting array.
Sure, you can do that but you are overlooking a real gimmee - the two arrays you are given will already be sorted.
def combine_arrays(A1, A2)
retVal = Array.CreateInstance(System::Int32, A1.Length + A2.Length - 1)
i = 0
j = 0
while i < A1.Length | j < A2.Length
if i < A1.Length and self.A1(i) < self.A2(j) then
self.retVal(i + j) = self.A1(i)
i += 1
else
self.retVal(i + j) = self.A2(j)
j += 1
end
end
return retVal
end
This is based on the same logic as Dale M's post, but in proper ruby:
def combine_arrays(arr1,arr2)
[].tap do |out|
i1 = i2 = 0
while i1 < arr1.size || i2 < arr2.size
v1 = arr1[i1]
v2 = arr2[i2]
if v1 && (!v2 || v1 < v2)
out << v1
i1 += 1
else
out << v2
i2 += 1
end
end
end
end
combine_arrays([1,3,5], [2,4,6])
Take a look at this one:
def merge(arr1, arr2)
arr2.each { |n| arr1 = insert_into_place(arr1, n) }
arr1.empty? ? arr2 : arr1
end
def insert_into_place(array, number)
return [] if array.empty?
group = array.group_by { |n| n >= number }
bigger = group[true]
smaller = group[false]
if bigger.nil?
number > smaller.last ? smaller << number : smaller.unshift(number)
else
(smaller << number) + bigger
end
end
I am doing a little preparation for a course I want to take. One of the questions they give as practice is the following:
Write a function, nearest_larger(arr, i) which takes an array and an
index. The function should return another index, j: this should
satisfy:
(a) arr[i] < arr[j], AND
(b) there is no j2 closer to i than j where arr[i] < arr[j].
In case of ties (see example below), choose the earliest (left-most)
of the two indices. If no number in arr is larger than arr[i],
return nil.
So the code I wrote was:
def function(arr,i)
k = arr.length
puts "nil" if arr.all? {|number| arr[i] >= number}
(0..(arr.length-1)).to_a.each do |j|
if arr[j] > arr[i]
k = j if((i-j).abs < k) ##
end
end
puts k
end
This function([1,2,6,5,10],3) returns 4 when it should be return 2.
I am having trouble addressing the scenario when there is a tie. I thought I designed my code to do this(I put ## where I think this is addressed.) Because it should be assigning the index to k if the distance is strictly less than so I don't know why it would return the right side. I hope that makes sense. Any help is appreciated.
From your current code:
def function(arr,i)
k = i - arr.length # the first result of (i-k).abs should be array length.
# returns -1 for testability purposes for `puts`
# this should be changed to return `nil`
return -1 if arr.all? {|number| arr[i] >= number}
(0...arr.length).to_a.each do |j|
if arr[j] > arr[i]
# since k is an index you should compare distance between i and j
# against the distance between i and k
k = j if((i-j).abs < (i-k).abs)
end
end
k
end
puts function([1,2,6,5,10], 0)
puts function([1,2,6,5,10], 1)
puts function([1,2,6,5,10], 2)
puts function([1,2,6,5,10], 3)
puts function([1,2,6,5,10], 4)
Output:
1
2
4
2
-1
k = arr.length
You have defaulted k to the length of the array but that's your return value. Best to make it something like nil so it doesn't confuse matters. I think that's where your return value 4 is coming from. If you add a new value onto the array it will the print 5, the new length of the array.
puts "nil" if arr.all? {|number| arr[i] >= number}
When you do the 'is there any value greater than my index value' test with all?, your not returning so the method would continue on and also print the length of the array (see above).
(0..(arr.length-1)).to_a.each do |j|
Enumerable (hence Array) has an each_with_index method so you don't need to specify/calculate the index's out the front of loops. You don't need to convert a range (0..x) to_a to loop around it either.
k = j if((i-j).abs < k) ##
You're comparing the distance of j to k itself, rather than to the distance of k.
You could cover both tests in a single loop of the array. With the < test, the left most answer in a tie takes cares of itself by the order you go over the array.
def find_closest_larger_index values, test_index, found = nil
values.each_with_index do |value,j|
found = j if value > values[test_index] and ( found.nil? or (test_index - j).abs < (test_index - found).abs )
end
found
end
Gives you
> find_closest_larger_index [1,2,6,5,10], 0
=> 1
> find_closest_larger_index [1,2,6,5,10], 1
=> 2
> find_closest_larger_index [1,2,6,5,10], 2
=> 4
> find_closest_larger_index [1,2,6,5,10], 3
=> 2
> find_closest_larger_index [1,2,6,5,10], 4
=> nil
Say I have an array that looks like:
a = [cat, dog, cat, mouse, rat, dog, cat]
How do I cycle through that, and do something with duplicates - e.g. say delete them?
In other words, if I did a.each do |i|, how do I evaluate a[0], against a[1], a[2], a[3]...and then when I find the one I want, say a[2] in this case has the first duplicate, I then push it to a stack or remove it or something.
I know how to evaluate keys, versus values...but how do I evaluate values against each other within the same array?
Thanks.
You can create a hash to store number of times any element is repeated. Thus iterating over array just once.
h = Hash.new(0)
['a','b','b','c'].each{ |e| h[e] += 1 }
Should result
{"a"=>1, "b"=>2, "c"=>1}
This works efficiently and is rather simple:
require 'set'
visited = Set.new
array.each do |element|
if visited.include?(element)
# duplicated item
else
# first appearance
visited << element
end
end
Try this:
class Array
def find_dups
uniq.map {|v| (self - [v]).size < (self.size - 1) ? v : nil}.compact
end
end
a = ['cat', 'dog', 'cat', 'mouse', 'rat', 'dog', 'cat']
print a - a.find_dups # Removes duplicates
find_dups will return elements that have duplicates
Try this:
array.inject({}){|h, e| h[e] = h[e].to_i + 1; h}
Use
a.uniq! to remove duplicates .
also checkout the ruby-doc.org where you can find more info on ruby's class methods .
A simple solution is to run a double loop:
a.each_with_index do |a1, idx1|
a.each_with_index do |a2, idx2|
next if idx1 >= idx2 # Don't compare element to itself
# and don't repeat comparisons already made
# do something with a pair of elements (a1, a2)
end
end
If you just want to eliminate duplicates, there's a method: Array#uniq.
This will print all the duplicates in an array:
array.inject(Hash.new(0)) { |hash,val|
hash[val] += 1;
hash
}.each_pair { |val,count|
puts "#{val} -> #{count}" if count > 1
}
The best way to do it is to compare it with a unique version of itself. If its the same then it has no duplicates, if not then duplicates exist.
unique_array = original_array.uniq
get a unique version of your array
if original_array == unique_array then return true else return false
compare it to your original array.
Simple!
If you just want to get rid of duplicates, the easiest thing to do is take the array and do array&array. Use the & operator.
If you want to know what those repeats are, just compare array to array&array.
If array is sortable, then something like below will return only the duplicates.
array.sort.each_cons(2).select {|p| p[0] == p[1] }.map &:first
Sorts the array, then maps it to consecutive pairs of elements, selects pairs which are same, maps to elements.
I'm trying to solve questions from Project Euler in Ruby one-liners, and I'm curious if there's a more elegant solution for question two:
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
Here is my one line solution in Ruby:
(1..32).inject([0,1]) {|arr, i| (arr << arr[-1] + arr[-2] if arr[-1] + arr[-2] <= 4000000) || arr}.inject(0) {|total, i| total += i.even? ? i : 0}
My main concern here is that I'm using the range (1..32) only because I happen to know that that's all that's necessary until numbers in the Fibonacci sequence begin to exceed 4,000,000. I would prefer that this be built into the one-line somehow, but I haven't been able to figure it out.
Semi-colons are not allowed!
My favorite solution to this is to use a Hash, the values of which can be determined by an anonymous function:
fibonacci = Hash.new{ |h,k| h[k] = k < 2 ? k : h[k-1] + h[k-2] }
fibonacci[6] # => 8
fibonacci[50] # => 12586269025
It's a "genuine" one-liner and very Ruby-ish.
Using a Ruby 1.9 Enumerator:
fib = Enumerator.new do |yielder|
i = 0
j = 1
loop do
i, j = j, i + j
yielder.yield i
end
end
p fib.take_while { |n| n <= 4E6 }
# => [1, 1, 2 ... 1346269, 2178309, 3524578]
As one line:
p Enumerator.new { |yielder| i, j = 0, 1; loop {i, j = j, i + j; yielder.yield i} }.take_while { |n| n <= 4E6}
Inspired on Alex's answer:
# Ruby 1.8.7
f = lambda { |x| x < 2 ? x : f.call(x-1) + f.call(x-2) }
puts f.call(6) #=> 8
# Ruby 1.9.2
f = ->(x){ x < 2 ? x : f[x-1] + f[x-2] }
puts f[6] #=> 8
My favorite is:
def fib(n)
(0..n).inject([1,0]) { |(a,b), _| [b, a+b] }[0]
end
from https://gist.github.com/1007228
How about this?
(((1 + 5 ** 0.5) / 2) ** 35 / 5 ** 0.5 - 0.5).to_i / 2
(See this answer for an explanation.)
Here's a ruby 2.0 solution, without using inject/reduce which is not lazy:
(1..Float::INFINITY).
lazy.
with_object([0,1]).
map { |x, last| last[1] = last[0] + (last[0] = last[1]) }.
select { |x| x % 2 == 0 }.
take_while { |x| x < 4_000_000 }.
reduce(&:+)
I don't particularly like the fibonacci generator, because it doesn't include the initial 0. This solution also takes advantage of the first odd number being F3 (F1 in this sequence generator).
A cleaner (Fibonacci-wise) and correct (In Liber Abaci's definition) solution would be:
(1..Float::INFINITY).
lazy.
with_object([0,1]).
map { |x, last| last[1] = last[0] + (last[0] = last[1]);last[0] }.
select { |x| x % 2 == 0 }.
take_while { |x| x < 4_000_000 }.
reduce(&:+)
This solution includes a semi-colon, but I don't know if it counts when used this way :).
[Update]
Here's a proper Fibonacci generator (starting on 0) solution, with no semi-colon (btw, is this a javascript semi-colon wars thingy ?!?) :)
(1..Float::INFINITY).
lazy.
with_object([0,1]).
map { |x, last| last[0].tap { last[1] = last[0] + (last[0] = last[1]) } }.
select { |x| x % 2 == 0 }.
take_while { |x| x < 4_000_000 }.
reduce(&:+)
Building on Alex's Hash, this may make you go blind, but it's one line, no semicolons and eliminates the range dependency. the instance_eval trick is very useful for oneliners and golf, although it's horrible Ruby.
Hash.new{|h,k|h[k]=k<2?k:h[k-1]+h[k-2]}.update(sum: 0,1=>1).instance_eval {self[:sum]+= self[keys.last+1].even? ? self[keys.last] : 0 while values.last < 4E6 || puts(fetch :sum)}
Outputs: 4613732
I warned you it was horrible. I can't make it actually return the value without using a semicolon, sorry.
I realize this is an ancient question and has been classed as answered but no-one manages to solve the question in one block, none of them actually give the sum of the even valued terms in one line and in one block and with no semi colons (just noticed that waynes does solve with one line but I thought a one block solution might be nice in response to aroth). here is a solution that does:
(1..Float::INFINITY).inject([0,1,0]){|a| if a[0]+a[1] < 4000000 then [a[1],a[0]+a[1],(a[0]+a[1]).even? ? a[2] + (a[0]+a[1]) : a[2]] else break a[2] end }
for a slightly clearer version with one semi colon.
(1..Float::INFINITY).inject([0,1,0]){|a| sum=a[0]+a[1]; if sum < 4000000 then [a[1],sum,sum.even? ? a[2] + sum : a[2]] else break a[2] end }
I figure I'll explain it too, three pieces of information get carried forward in the array (as a at each iteration) the first fibonacci number, the second fibonacci number and the sum of the even terms. bearing this in mind I think this code is quite clear ruby.
it should be noted that this is basically the same as clems except in one block
puts (1..20).inject([0, 1]){|Fibonacci| Fibonacci << Fibonacci.last(2).inject(:+) }
This is the best solution I ever had used to print the Fibonacci series using inject keyword.
Explanation:
1) .inject([0,1]) will hold the default value (0) first value of collection (1) element of the series.
2) At first Fibonacci object will have 0, 1 using Fibonacci.last(2) that will be passed through inject
3) .inject(:+) will add the 0+1
4) This will add 0+1 = 1 and then will be pushed to Fibonacci which on next iteration with outer inject([0,1]) will become inject(1,2)
here 1 is the value after sum (0+1) and 2 is the next iteration value of collection.
and so on till the end of collection
So the series will be like
0
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181
6765
10946
I can think of 4 ways for now to achieve the fibonacci goal!
Using a stabby lambda:
puts 'Fibonacci Sequence in a Line: ', ->(a=1, b=0) { 10.times.collect { (a, b = b, a + b)[0] } }.call
This evaluates 10 series. But if you want to get the user's number:
puts 'Fibonacci Sequence in a Line: ', ->(a=1, b=0) { gets.to_i.times.collect { (a, b = b, a + b)[0] } }.call
Using the tap method:
[0, 1].tap { |a| 10.times { a.push(a[-1] + a[-2]) } }
Using the reduce / inject method:
(1..10).reduce([0, 1]) { |a| a.push(a.last(2).sum) }
or
10.times.reduce([0, 1]) { |a| a.push(a.last(2).sum) }
Using the each_with_object or map.with_object method:
10.times.each_with_object([0, 1]) { |_, a| a.push(a.last(2).sum) }
Note: If you don't have Ruby 2.4+ you may not have the sum method. In that case, you can add the last two elements with ary[-2] + ary[-1] or ary.last(2).reduce(:+).
Coming to your problem:
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
[0, 1].tap { |a| until (s = a.last(2).sum) > 4_000_000 do a.push(s) end }.select(&:even?).sum
Or (which is not that great):
[0, 1].tap { |a| loop while a.push(a.last(2).sum)[-1] < 4_000_000 }.tap(&:pop).select(&:even?).sum
Outputs:
4613732
Hope this helps!
Returns correct values up to Fib(70), beyond that just an approximation. But extremely fast:
(((Math.sqrt(5.0) + 1.0) / 2.0)**n / Math.sqrt(5.0) + 0.5).floor
(see https://en.wikipedia.org/wiki/Fibonacci_number#Computation_by_rounding for explanation)
With the new lazy in ruby 2.0, you can write like this.
puts (1..Float::INFINITY).lazy.map{|n| (0..n).inject([1,0]) {|(a,b), _| [b, a+b]}[0] }.take_while{|n| n < 4000000}.select{|x| x % 2 == 0}.reduce(:+)
As a summarizing solution for the answers above, with my humble additions:
32.
times.
lazy.
with_object([0, 1]).map { |_, fib| fib[1] = fib[0] + fib[0] = fib[1]; fib[0] }.
take_while(&:>.to_proc.curry(2)[4*10**6]).
select(&:even?).
inject(:+)
I don't really like how currying looks, but didn't want it to look similar to other answers. Alternative take_while just for the case:
take_while { |value| value < 4*10**6 }.
Here's a one line ruby solution to Euler prob #2
(0..4000000).take_while{|i| (0..i).reduce([1,0]){|(a,b), _| [b, a+b]}[0] <= 4000000 }.map{|i| (0..i).reduce([1,0]){|(a,b), _| [b, a+b]}[0] }.select{|i| i%2 == 0}.reduce(:+)
Or for better readability??
(0..4000000) .
take_while {|i| (0..i).reduce([1,0]){|(a,b), _| [b, a+b]}[0] <= 4000000} .
map {|i| (0..i).reduce([1,0]){|(a,b), _| [b, a+b]}[0]} .
select {|i| i%2 == 0} .
reduce(:+)
(1..32).inject([0, 1]) { |fib| fib << fib.last(2).inject(:+) }
Here is my one liner, with the #fib table being populated as we get the method returns..
#fib=[0,1];def fib num; return 0 if num < 0; #fib[num]||=fib(num-1)+fib(num-2);end
Simple and elegant is the best way, right?
a0 = 1; a1 = 1; 20.times {|i| b = a0 + a1; a0 = a1; a1 = b; puts b };
Output:
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181
6765
10946
17711
=> 20