I'm amazed with Ruby's syntax, I can only describe it in one word: comfortable.
EDIT: I think I wasn't clear. I want an easy way to exit loops with conditions.
Sadly, I can't find how to do this Java code in Ruby:
Assume:
array = [1,2,3,4]
array2 = [1,2,3,4]
boolean condition = false;
for(int i = 0; i < array.length && !condition; i++)
{
for(int j = 0; j < array2.length && !condition; j++)
{
condition = (array[i] + array2[j] + 1 == 7);
}
}
if(condition)
{
System.out.println("Two elements of the arrays + 1 sum 7")
}
I love Ruby's one liners... But I can't even do this with full open loops...
I'm looking for something like this (each_while is made up):
array.each_while(condition && condition2) { SomeAction }
Which is the simplest way to do this in Ruby?
Most of the loops I work with have exiting conditions to optimize them. Everything I find on the internet is not acceptable for Ruby's beautiful syntax because it is even worse than Java, and we all know Java ain't pretty.
Some solution I found in the web:
catch "BreakOuterLoop" do
for i in 1..10
print "out #{i}\n"
for j in 1..10
print "in #{j}\n"
throw "BreakOuterLoop" if i+j > 16
end
end
end
Just awful...
require 'matrix'
Matrix[0...rows, 0...cols].each_with_index do |e, row, col|
next unless [cond1, cond2, cond3].reduce :&
# code
end
array1.each.with_index.lazy.take_while { cond1 }.each do |e1, i1|
array2.each.with_index.lazy.take_while { cond2 }.each do |e2, i2|
# do some stuff
end
end
Loop with condition
You could use break :
array1.each do |x|
break unless condition && condition2
array2.each do |y|
break unless condition3
# do_something
end
end
end
If you need the indices in your conditions :
array1.each_with_index do |x,i|
break unless condition && condition2
array2.each_with_index do |y,j|
break unless condition3
# do_something
end
end
end
Specific problem
Boolean
For your updated problem, you can use any?. It is exactly what you wanted to do. It iterates as long as a condition isn't true, and returns a value ASAP :
array = [1,2,3,4]
array2 = [1,2,3,4]
puts array.product(array2).any?{|a,b| a + b + 1 == 7 }
#=> true
Or :
puts array.any?{|a| array2.any?{ |b| a + b + 1 == 7 } }
#=> true
puts array.any?{|a| array2.any?{ |b| a + b + 1 == 12 } }
#=> false
The second example should be faster, because not every pair is created : As soon as one is found, true is returned.
Pair
If you want to know for which pair the condition is true, you can use find:
p array.product(array2).find { |a, b| a + b + 1 == 7 }
#=> [2,4]
p array.product(array2).find { |a, b| a + b + 1 == 12 }
#=> nil
Optimization for huge arrays
The above code will run slow for huge arrays.
You could convert the biggest array to a Set, and use a direct lookup :
require 'set'
array = [1, 2, 3, 4]
array2 = [1, 2, 3, 4]
set2 = array2.to_set
sum = 7 - 1
x1 = array.find { |x| set2.include?(sum - x) }
if x1
puts "#{x1} + #{sum - x1} + 1 = #{sum + 1}"
end
#=> 2 + 4 + 1 = 7
array.length.times do |i|
break unless condition_1 && condition_2
# some action
end
break will stop the loop as soon as the conditions are no longer met
Regarding the loop matrix
Of course you can nest a loop within a loops within a loop, but that is definitely not the ruby way. I'm sure there is a nicer solution to whatever problem may arise.
As stated before, there is a prettier functional solution for probably any specific use case you can think of. I will try to answer the more general question, which is how to convert this java code:
int somethingYouWillMutate = 0; // any types or values or number of things
for(int i = 0; i < array.length && condition && condition2; i++) {
for(int j = 0; j < array2.length && condition; j++) {
someAction(array[i], array2[j], somethingYouWillMutate);
}
}
To ruby:
something_you_will_mutate = 0
array.product(array2).each do |e1, e2|
break unless condition && condition2
some_action(e1, e2)
end
Note:
while c1 && c2 =:=
while true; break if !(c1 && c2) =:=
while true; break unless c1 && c2
If you want the indices as well:
array_indexed = array.each_with_index.to_a
array2_indexed = array2.each_with_index.to_a
array_indexed.product(array2_indexed).each do |(e1, i1), (e2, i2)|
break unless condition && condition2
some_action(e1, e2, i1, i2, something_you_will_mutate)
end
Note: If you want an even more generic solution (with 3 or more arrays for example):
[array, array2, array3...].
map(&:each_with_index).
map(&:to_a).
reduce(:product).
map(&:flatten).
each do |e1, i1, e2, i2, e3, i3...|
break unless condition && condition2 && condition3...
some_action(e1, e2, i1, i2, e3, i3..., something_you_will_mutate)
end
Related
I was playing around with some implementations of Quicksort in Ruby. After implementing some of the inlace algorithms, I felt that using Ruby's partition method, even though it would not provide an in-place solution, it would provide a very nice readable solution.
My first solution was this, which other than always using the last element of the array as the pivot, seemed pretty nice.
def quick_sort3(ary)
return ary if ary.size <= 1
left,right = ary.partition { |v| v < ary.last }
pivot_value = right.pop
quick_sort3(left) + [pivot_value] + quick_sort3(right)
end
After some searching I found this answer which had a very similar solution with a better choice of the initial pivot, reproduced here using the same variable names and block passed to partition.
def quick_sort6(*ary)
return ary if ary.empty?
pivot_value = ary.delete_at(rand(ary.size))
left,right = ary.partition { |v| v < pivot_value }
return *quick_sort6(*left), pivot_value, *quick_sort6(*right)
end
I felt I could improve my solution by using the same method to select a random pivot.
def quick_sort4(ary)
return ary if ary.size <= 1
pivot_value = ary.delete_at(rand(ary.size))
left,right = ary.partition { |v| v < pivot_value }
quick_sort4(left) + [pivot_value] + quick_sort4(right)
end
The down side to this version quick_sort4 vs the linked answer quick_sort6, is that quick_sort4 changes the input array, while quick_sort6 does not. I am assuming this is why Jorg chose to receive the splat array vs array?
My fix for this was to simply duplicate the passed in array and then perform the delete_at on the copied array rather than the original array.
def quick_sort5(ary_in)
return ary_in if ary_in.size <= 1
ary = ary_in.dup
pivot_value = ary.delete_at(rand(ary.size))
left,right = ary.partition { |v| v < pivot_value }
quick_sort5(left) + [pivot_value] + quick_sort5(right)
end
My question is there any significant differences between quick_sort6 which uses the splats and quick_sort5 which uses dup? I am assuming the use of the splats was to avoid changing the input array, but is there something else I am missing?
In terms of performance, quick_sort6 is your best bet. Using some random data:
require 'benchmark'
def quick_sort3(ary)
return ary if ary.size <= 1
left,right = ary.partition { |v| v < ary.last }
pivot_value = right.pop
quick_sort3(left) + [pivot_value] + quick_sort3(right)
end
def quick_sort6(*ary)
return ary if ary.empty?
pivot_value = ary.delete_at(rand(ary.size))
left,right = ary.partition { |v| v < pivot_value }
return *quick_sort6(*left), pivot_value, *quick_sort6(*right)
end
def quick_sort4(ary)
return ary if ary.size <= 1
pivot_value = ary.delete_at(rand(ary.size))
left,right = ary.partition { |v| v < pivot_value }
quick_sort4(left) + [pivot_value] + quick_sort4(right)
end
def quick_sort5(ary_in)
return ary_in if ary_in.size <= 1
ary = ary_in.dup
pivot_value = ary.delete_at(rand(ary.size))
left,right = ary.partition { |v| v < pivot_value }
quick_sort5(left) + [pivot_value] + quick_sort5(right)
end
random_arrays = Array.new(5000) do
Array.new(500) { rand(1...500) }.uniq
end
Benchmark.bm do |benchmark|
benchmark.report("quick_sort3") do
random_arrays.each do |ra|
quick_sort3(ra.dup)
end
end
benchmark.report("quick_sort6") do
random_arrays.each do |ra|
quick_sort6(ra.dup)
end
end
benchmark.report("quick_sort4") do
random_arrays.each do |ra|
quick_sort4(ra.dup)
end
end
benchmark.report("quick_sort5") do
random_arrays.each do |ra|
quick_sort5(ra.dup)
end
end
end
Gives as result
user system total real
quick_sort3 1.389173 0.019380 1.408553 ( 1.411771)
quick_sort6 0.004399 0.000022 0.004421 ( 0.004487)
quick_sort4 1.208003 0.002573 1.210576 ( 1.214131)
quick_sort5 1.458327 0.000867 1.459194 ( 1.459882)
The problem with splat style in this case is that it would create an awkward API.
Most times the consumer code would have an array of things that need to be sorted:
stuff = [1, 2, 3]
sort(stuff)
The splat style makes the consumers do this instead:
stuff = [1, 2, 3]
sort(*stuff)
The two calls might end up doing the same thing, but as a user I am sorting an array, therefore I expect to pass the array to the method, not pass each array element individually to the method.
Another label for this phenomenon in abstraction leakage - you are allowing the implementation of the sort method define its interface. Usually in Ruby this is frowned upon.
if i run the code, it will stop and not do anything and i am unable to type. seems to be an infinite loop.
the problem seems to be the end until loop, however if i take that out, my condition will not be met.
can anyone find a solution? i have tried all the loops that i can think of.
/. 2d array board ./
board = Array.new(10) { Array.new(10, 0) }
/. printing board ./
if board.count(5) != 5 && board.count(4) != 4 && board.count(3) != 3
for i in 0..9
for j in 0..9
board[i][j] = 0
end
end
aircraftcoord1 = (rand*10).floor
aircraftcoord2 = (rand 6).floor
aircraftalign = rand
if aircraftalign < 0.5
for i in 0..4
board[aircraftcoord2+i][aircraftcoord1] = 5
end
else
for i in 0..4
board[aircraftcoord1][aircraftcoord2+i] = 5
end
end
cruisercoord1 = (rand*10).floor
cruisercoord2 = (rand 7).floor
cruiseralign = rand
if cruiseralign < 0.5
for i in 0..3
board[cruisercoord2+i][cruisercoord1] = 4
end
else
for i in 0..3
board[cruisercoord1][cruisercoord2+i] = 4
end
end
destroyercoord1 = (rand*10).floor
destroyercoord2 = (rand 8).floor
destroyeralign = rand
if destroyeralign < 0.5
for i in 0..2
board[destroyercoord2+i][destroyercoord1] = 3
end
else
for i in 0..2
board[destroyercoord1][destroyercoord2+i] = 3
end
end
end until board.count(5) == 5 && board.count(4) == 4 && board.count(3) == 3
print " "
for i in 0..9
print i
end
puts
for i in 0..9
print i
for j in 0..9
print board[i][j]
end
puts
end
The line board.count(5) == 5 ... will never be true because board is a two-dimensional array. I can't tell what the condition should be, but it could look something like:
board[5].count(5) == 5
factorial_sum(5) should return 3. The error I'm getting is that "inject is an undefined method". I was also wondering if it's possible to combine the two functions. I wasn't sure as I am just starting out on recursion. Thanks!
def factorial_sum(x)
factorial = factorial(x)
factorial.to_s.split('').collect { |i| i.to_i }
sum = factorial.inject { |sum, n| sum + n }
end
def factorial(x)
if x < 0
return "Negative numbers don't have a factorial"
elsif x == 0
1
else
factorial = x * factorial(x - 1)
end
end
puts factorial_sum(5)
factorial.to_s.split('').collect { |i| i.to_i }
This line is a no-op. You build a list and then throw it away. You probably meant factorial = ...
I have to say though that this would be pretty easy to find with a little effort and some print statements...
By the way, here's a slightly more concise way:
(1..x).reduce(:*).to_s.chars.map(&:to_i).reduce(:+)
A direct way without temporarily converting it into strings, and without recursion.
s, q = 0, 120
while q > 0
q, r = q.divmod(10)
s += r
end
s # => 3
This seems like a pretty common question. Sadly I could not find it on SO. If this is a duplicate question; I apologize for that.
Say I have two integer arrays A and B:
A = [17, 3, 9, 11, 11, 15, 2]
B = [1, 13]
I need to return a true or a false if any element of array A is less than any element of array B.
The trivial way to do this was use 2 each loops (O(n^2) complexity)
def is_greater?(a,b)
retVal = false
b.each { |element|
a.each { |value|
if (value < element)
retVal = true
break
end
}
}
return retVal
end
is_greater?(A,B) => true
I also sorted out the elements in both the arrays and then used a single while loop to determine whether the element in A is less than that in B.
A.sort!
B.sort!
def is_greater?(a,b)
retVal = false
i = 0
j = 0
while (i < a.length && j < b.length)
if (a[i] < b[j])
retVal = true
break
elsif (a[i] == b[j])
i = i + 1
j = j + 1
else
j = j + 1
end
end
return retVal
end
is_greater?(A,B) => true
I was wondering whether there is an efficient, precise way to do it in terms of lines of code. I was trying to figure out how to use the any? block, but it did not make any sense to me.
Yes, you can use Enumerable methods #any? and #min
For each item in a, return true if it is less than max:
max = b.max
a.any?{|x| x < max}
It should be enough to just check the minimum of the first array against the maximum of the second.
a.min < b.max
The only way this conditional returns false is if every element is b is less than every element in a.
The complexity is O(m+n) which is the single iteration through both a and b.
I'm trying to learn Ruby, and am going through some of the Project Euler problems. I solved problem number two as such:
def fib(n)
return n if n < 2
vals = [0, 1]
n.times do
vals.push(vals[-1]+vals[-2])
end
return vals.last
end
i = 1
s = 0
while((v = fib(i)) < 4_000_000)
s+=v if v%2==0
i+=1
end
puts s
While that works, it seems not very ruby-ish—I couldn't come up with any good purely Ruby answer like I could with the first one ( puts (0..999).inject{ |sum, n| n%3==0||n%5==0 ? sum : sum+n }).
For a nice solution, why don't you create a Fibonacci number generator, like Prime or the Triangular example I gave here.
From this, you can use the nice Enumerable methods to handle the problem. You might want to wonder if there is any pattern to the even Fibonacci numbers too.
Edit your question to post your solution...
Note: there are more efficient ways than enumerating them, but they require more math, won't be as clear as this and would only shine if the 4 million was much higher.
As demas' has posted a solution, here's a cleaned up version:
class Fibo
class << self
include Enumerable
def each
return to_enum unless block_given?
a = 0; b = 1
loop do
a, b = b, a + b
yield a
end
end
end
end
puts Fibo.take_while { |i| i < 4000000 }.
select(&:even?).
inject(:+)
My version based on Marc-André Lafortune's answer:
class Some
#a = 1
#b = 2
class << self
include Enumerable
def each
1.upto(Float::INFINITY) do |i|
#a, #b = #b, #a + #b
yield #b
end
end
end
end
puts Some.take_while { |i| i < 4000000 }.select { |n| n%2 ==0 }
.inject(0) { |sum, item| sum + item } + 2
def fib
first, second, sum = 1,2,0
while second < 4000000
sum += second if second.even?
first, second = second, first + second
end
puts sum
end
You don't need return vals.last. You can just do vals.last, because Ruby will return the last expression (I think that's the correct term) by default.
fibs = [0,1]
begin
fibs.push(fibs[-1]+fibs[-2])
end while not fibs[-1]+fibs[-2]>4000000
puts fibs.inject{ |sum, n| n%2==0 ? sum+n : sum }
Here's what I got. I really don't see a need to wrap this in a class. You could in a larger program surely, but in a single small script I find that to just create additional instructions for the interpreter. You could select even, instead of rejecting odd but its pretty much the same thing.
fib = Enumerator.new do |y|
a = b = 1
loop do
y << a
a, b = b, a + b
end
end
puts fib.take_while{|i| i < 4000000}
.reject{|x| x.odd?}
.inject(:+)
That's my approach. I know it can be less lines of code, but maybe you can take something from it.
class Fib
def first
#p0 = 0
#p1 = 1
1
end
def next
r =
if #p1 == 1
2
else
#p0 + #p1
end
#p0 = #p1
#p1 = r
r
end
end
c = Fib.new
f = c.first
r = 0
while (f=c.next) < 4_000_000
r += f if f%2==0
end
puts r
I am new to Ruby, but here is the answer I came up with.
x=1
y=2
array = [1,2]
dar = []
begin
z = x + y
if z % 2 == 0
a = z
dar << a
end
x = y
y = z
array << z
end while z < 4000000
dar.inject {:+}
puts "#{dar.sum}"
def fib_nums(num)
array = [1, 2]
sum = 0
until array[-2] > num
array.push(array[-1] + array[-2])
end
array.each{|x| sum += x if x.even?}
sum
end