Is there way to assign and break within the block? - ruby

I know I can write it this way successfully:
def test_find_first_multiple_of_3
numbers = [2, 8, 9, 27, 24, 5]
found = nil
numbers.each do |number|
if number % 3 == 0
found = number
break
end
end
assert_equal 9, found
end
Is there anyway to do within the block? What am I missing? Or is just not possible?
numbers.each { |n| n % 3 == 0 ? (found = n then break) : nil }
def test_find_first_multiple_of_3
numbers = [2, 8, 9, 27, 24, 5]
found = nil
numbers.each { |n| n % 3 == 0 ? (found = n then break) : nil }
assert_equal 9, found
end

As pointed by other answers, there are other ruby ways to accomplish your algorithm goal, like using the .find method:
found = numbers.find { |n| (n % 3).zero? }
This way, you don't need to break your loop.
But, specifically answering your question, there are some ways to break the loop in the same line, if you want so:
use ; (multiple statements separator):
numbers.each { |n| n % 3 == 0 ? (found = n; break) : nil }
or put your assigment after break, that works too:
numbers.each { |n| n % 3 == 0 ? (break found = n) : nil }
I just used your code in the example, but, again, that's not a good pratice, because, as well pointed by #the Tin Man, "hurts readability and maintenance".
Also, as pointed by #akuhn, you don't need to use ternary here. You can simply use:
numbers.each { |n| break found = n if n % 3 == 0 }
** EDITED to include suggestions from #the Tin Man, #akuhn and #Eric Duminil, in order to warn OP that there are other alternatives to run his task, that doesn't need to break loop. The original answer was written just to answer OP's question specifically (one line break loop), without the code structure concern.

With common Ruby idioms your can write:
def test_find_first_multiple_of_3
numbers = [2, 8, 9, 27, 24, 5]
found = numbers.find { |n| (n % 3).zero? }
assert_equal 9, found
end

Yes, both break and next take an argument.
For your example though, best use find
founds = numbers.find { |n| n % 3 == 0 }
Generally in Ruby there is rarely a reason to break out of a loop.
You can typically use find or any of the other functions provided by the Enumerable module, like take_while and drop_while…

You can use the enumerable method find to find the first item that matches. Usually you will want to use enumerable methods like cycle, detect, each, reject, and others to make the code more compact while remaining understandable:
def test_find_first_multiple_of_3
numbers = [2, 8, 9, 27, 24, 5]
found = numbers.find { |number| number % 3 == 0 }
assert_equal 9, found
end

Related

Count of positives / sum of negatives Syntax Error

So I am currently working on the following problem in code wars:
Return an array, where the first element is the count of positive numbers and the second element is sum of negative numbers. If the input array is empty or null, return an empty array.
I came up with the following code, it ain't pretty, but I know it should work:
def count_positives_sum_negatives(lst)
pos, neg = 0, 0
lst.each do |num|
if num < 0
neg += num
else
pos++
end
end
[pos, neg]
end
I then call the following test:
count_positives_sum_negatives([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -11, -12, -13, -14, -15])
and it should return => [10,-65]
However its returning the following error:
(repl):11: syntax error, unexpected keyword_end
(repl):17: syntax error, unexpected end-of-input, expecting keyword_end
..., 10, -11, -12, -13, -14, -15])
...
Can anyone give me an explanation of why this is occurring?
As people have pointed out the error here is x++ is not valid Ruby, that you need x +=1 instead. The postfix and prefix increment operator is a point of wild confusion in most languages so Ruby has never implemented one. As in, what is the result of x++ + x++ + ++x?
Here's a strategy that's different using partition to first split the array, then collapse that together using inject:
positives, negatives = list.partition(&:positive?)
[ positives.length, negatives.inject(0, &:+) ]
# => [10,-65]
Here is another way you could do that.
def count_pos_sum_neg(arr)
return [] if arr.empty?
arr.each_with_object([0,0]) do |n,a|
a[0] += 1 if n > 0
a[1] += n if n < 0
end
end
count_pos_sum_neg [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -11, -12, -13, -14, -15]
#=> [10, -65]
In actual application, returning a hash may be more convenient.
def count_pos_sum_neg(arr)
return [] if arr.empty?
arr.each_with_object({count_pos: 0, sum_neg: 0}) do |n,h|
h[:count_pos] += 1 if n > 0
h[:sum_neg] += n if n < 0
end
end
count_pos_sum_neg [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -11, -12, -13, -14, -15]
#=> {:count_pos=>10, :sum_neg=>-65}
THe problem is pos++ which is not a valid operation in Ruby. It's being interpreted as an addition followed by a unary + but there's no number after the unary so it's expecting the next line to contain a value.
But the next line is end which is unexpected (hence the first error unexpected keyword_end) and because the end is now consumed you are missing an end for the method (hence the second error expecting keyword_end
So just change the line to...
pos += 1
Yet another variant using inject:
def count_pos_sum_neg(arr)
arr.inject([0, 0]) do |(count, sum), n|
if n > 0
[count + 1, sum]
else
[count, sum + n]
end
end
end
Or compressed:
def count_pos_sum_neg(arr)
arr.inject([0, 0]) { |(c, s), n| n > 0 ? [c + 1, s] : [c, s + n] }
end
The code doesn't check "If the input array is empty or null".
As I suspected your initial approach which is easy to read and simple, is actually fast too. Some results from a fruity comparison (code compacted):
require 'fruity'
arr = ((-1000..-1).to_a + (1..1000).to_a).shuffle
#various methods etc as defined in other answers.
compare do
wnamen { ar = arr; wnamen_method ar }
tadman { ar = arr; tadman_method ar }
cary { ar = arr; cary_method ar }
cary2 { ar = arr; cary2_method ar }
stefan { ar = arr; stefan_method ar }
stefan2 { ar = arr; stefan2_method ar }
end
results:
Running each test 8 times. Test will take about 1 second.
wnamen is faster than tadman by 2.0x ± 0.1
tadman is similar to stefan2
stefan2 is similar to stefan
stefan is similar to cary
cary is faster than cary2 by 19.999999999999996% ± 10.0% (results differ: [1000, -500500] vs {:count_pos=>1000, :sum_neg=>-500500})
All the other approaches are of course interesting and worth knowing nonetheless.

Ruby - method for generating prime numbers

I'm writing a method - prime_numbers - that, when passed a number n, returns an n number of primes. It should not rely on Ruby's Prime class. It should behave like so:
prime_numbers 3
=> [2, 3, 5]
prime_numbers 5
=> [2, 3, 5, 7, 11]
My first attempt at this method is as follows:
def prime_numbers(n)
primes = []
i = 2
while primes.length < n do
divisors = (2..9).to_a.select { |x| x != i }
primes << i if divisors.all? { |x| i % x != 0 }
i += 1
end
primes
end
Edit: As pointed out, the current method is at fault by being limited to take into account divisors only up to 9. As a result, any perfect square composed of two equal primes greater than 9 is treated as a prime itself.
If anyone has input or tips they can share on better ways to approach this, it would be greatly appreciated.
Note that if the number is composite it must have a divisor less than or equal to $\sqrt{n}$. So you really only have to check up to $sqrt{n}$ to find a divisor.
Got a good idea for your implementation:
#primes = []
def prime_numbers(n)
i = 2
while #primes.size < n do
#primes << i if is_prime?(i)
i += 1
end
#primes
end
def is_prime?(n)
#primes.each { |prime| return false if n % prime == 0 }
true
end
This is based on the idea that non-prime numbers have prime factors :)
In Ruby 1.9 there is a Prime class you can use to generate prime numbers, or to test if a number is prime:
require 'prime'
Prime.take(10) #=> [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
Prime.take_while {|p| p < 10 } #=> [2, 3, 5, 7]
Prime.prime?(19) #=> true
Prime implements the each method and includes the Enumerable module, so you can do all sorts of fun stuff like filtering, mapping, and so on.

Looping through an array with step

I want to look at every n-th elements in an array. In C++, I'd do this:
for(int x = 0; x<cx; x+=n){
value_i_care_about = array[x];
//do something with the value I care about.
}
I want to do the same in Ruby, but can't find a way to "step". A while loop could do the job, but I find it distasteful using it for a known size, and expect there to be a better (more Ruby) way of doing this.
Ranges have a step method which you can use to skip through the indexes:
(0..array.length - 1).step(2).each do |index|
value_you_care_about = array[index]
end
Or if you are comfortable using ... with ranges the following is a bit more concise:
(0...array.length).step(2).each do |index|
value_you_care_about = array[index]
end
array.each_slice(n) do |e, *_|
value_i_care_about = e
end
Just use step() method from Range class which returns an enumerator
(1..10).step(2) {|x| puts x}
We can iterate while skipping over a range of numbers on every iteration e.g.:
1.step(10, 2) { |i| print "#{i} "}
http://www.skorks.com/2009/09/a-wealth-of-ruby-loops-and-iterators/
So something like:
array.step(n) do |element|
# process element
end
class Array
def step(interval, &block)
((interval -1)...self.length).step(interval) do |value|
block.call(self[value])
end
end
end
You could add the method to the class Array
What about:
> [1, 2, 3, 4, 5, 6, 7].select.each_with_index { |_,i| i % 2 == 0 }
=> [1, 3, 5, 7]
Chaining of iterators is very useful.
This is a great example for the use of the modulo operator %
When you grasp this concept, you can apply it in a great number of different programming languages, without having to know them in and out.
step = 2
["1st","2nd","3rd","4th","5th","6th"].each_with_index do |element, index|
puts element if index % step == 1
end
#=> "2nd"
#=> "4th"
#=> "6th"

List of prime numbers using Array methods

I have a code to get list of prime numbers:
def primes_numbers num
primes = [2]
3.step(Math.sqrt(num) + 1, 2) do |i|
is_prime = true
primes.each do |p| # (here)
if (p > Math.sqrt(i) + 1)
break
end
if (i % p == 0)
is_prime = false
break
end
end
if is_prime
primes << i
end
end
primes
end
Is it possible rewrite code using Array methods (select, collect and so on...)?
Something like:
s = (3..n)
s.select { |x| x % 2 == 1}.select{ |x| ..... }
The problem is that I need to iterate throught result array (comment 'here') in the select method.
Ruby 1.9 has a very nice Prime class:
http://www.ruby-doc.org/core-1.9/classes/Prime.html
But I'm assuming you don't care about any standard classes, but want to see some code, so here we go:
>> n = 100 #=> 100
>> s = (2..n) #=> 2..100
>> s.select { |num| (2..Math.sqrt(num)).none? { |d| (num % d).zero? }}
#=> [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
Note: I wrote it this way because you wanted Enumerable methods, for efficiency's sake you probably want to read up on prime finding methods.
You can list prime numbers like this as well.
Example Array: ar = (2..30).to_a
ar.select{ |n| (2..n).count{ |d| (n % d).zero? } == 1 }
Features :
Check a number is Prime, get a number factors and get list of prime numbers and also you can easily transform it in any language you want
As Ruby has its own Prime class so you don't need to worry
but if you want to do it your own without using ruby core things
n=100 #=> a
def prime_numbers(n)
prime_numbers = []
(1..n).each do |number|
prime_numbers << number if is_prime(number)
end
prime_numbers
end
def is_prime(n)
if factors(n).count > 2
return true
end
return false
end
# find factors of a number
def factors(n)
factors = []
(1..n).each {|d| factors << d if (n%d).zero?}
factors
end
Note: There are three functions involved and I deliberately do this for beginners, So that they can easily understand about it
Optimization Guide:
1) You can start loop from 2 and end at n-1 if you want to save iterations
2) use Ruby core functions and enjoy things :)

List comprehension in Ruby

To do the equivalent of Python list comprehensions, I'm doing the following:
some_array.select{|x| x % 2 == 0 }.collect{|x| x * 3}
Is there a better way to do this...perhaps with one method call?
How 'bout:
some_array.map {|x| x % 2 == 0 ? x * 3 : nil}.compact
Slightly cleaner, at least to my taste, and according to a quick benchmark test about 15% faster than your version...
If you really want to, you can create an Array#comprehend method like this:
class Array
def comprehend(&block)
return self if block.nil?
self.collect(&block).compact
end
end
some_array = [1, 2, 3, 4, 5, 6]
new_array = some_array.comprehend {|x| x * 3 if x % 2 == 0}
puts new_array
Prints:
6
12
18
I would probably just do it the way you did though.
I made a quick benchmark comparing the three alternatives and map-compact really seems to be the best option.
Performance test (Rails)
require 'test_helper'
require 'performance_test_help'
class ListComprehensionTest < ActionController::PerformanceTest
TEST_ARRAY = (1..100).to_a
def test_map_compact
1000.times do
TEST_ARRAY.map{|x| x % 2 == 0 ? x * 3 : nil}.compact
end
end
def test_select_map
1000.times do
TEST_ARRAY.select{|x| x % 2 == 0 }.map{|x| x * 3}
end
end
def test_inject
1000.times do
TEST_ARRAY.inject([]) {|all, x| all << x*3 if x % 2 == 0; all }
end
end
end
Results
/usr/bin/ruby1.8 -I"lib:test" "/usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb" "test/performance/list_comprehension_test.rb" -- --benchmark
Loaded suite /usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader
Started
ListComprehensionTest#test_inject (1230 ms warmup)
wall_time: 1221 ms
memory: 0.00 KB
objects: 0
gc_runs: 0
gc_time: 0 ms
.ListComprehensionTest#test_map_compact (860 ms warmup)
wall_time: 855 ms
memory: 0.00 KB
objects: 0
gc_runs: 0
gc_time: 0 ms
.ListComprehensionTest#test_select_map (961 ms warmup)
wall_time: 955 ms
memory: 0.00 KB
objects: 0
gc_runs: 0
gc_time: 0 ms
.
Finished in 66.683039 seconds.
15 tests, 0 assertions, 0 failures, 0 errors
There seems to be some confusion amongst Ruby programmers in this thread concerning what list comprehension is. Every single response assumes some preexisting array to transform. But list comprehension's power lies in an array created on the fly with the following syntax:
squares = [x**2 for x in range(10)]
The following would be an analog in Ruby (the only adequate answer in this thread, AFAIC):
a = Array.new(4).map{rand(2**49..2**50)}
In the above case, I'm creating an array of random integers, but the block could contain anything. But this would be a Ruby list comprehension.
I discussed this topic with Rein Henrichs, who tells me that the best performing solution is
map { ... }.compact
This makes good sense because it avoids building intermediate Arrays as with the immutable usage of Enumerable#inject, and it avoids growing the Array, which causes allocation. It's as general as any of the others unless your collection can contain nil elements.
I haven't compared this with
select {...}.map{...}
It's possible that Ruby's C implementation of Enumerable#select is also very good.
I've just published the comprehend gem to RubyGems, which lets you do this:
require 'comprehend'
some_array.comprehend{ |x| x * 3 if x % 2 == 0 }
It's written in C; the array is only traversed once.
An alternative solution that will work in every implementation and run in O(n) instead of O(2n) time is:
some_array.inject([]){|res,x| x % 2 == 0 ? res << 3*x : res}
Enumerable has a grep method whose first argument can be a predicate proc, and whose optional second argument is a mapping function; so the following works:
some_array.grep(proc {|x| x % 2 == 0}) {|x| x*3}
This isn't as readable as a couple of other suggestions (I like anoiaque's simple select.map or histocrat's comprehend gem), but its strengths are that it's already part of the standard library, and is single-pass and doesn't involve creating temporary intermediate arrays, and doesn't require an out-of-bounds value like nil used in the compact-using suggestions.
This is more concise:
[1,2,3,4,5,6].select(&:even?).map{|x| x*3}
[1, 2, 3, 4, 5, 6].collect{|x| x * 3 if x % 2 == 0}.compact
=> [6, 12, 18]
That works for me. It is also clean. Yes, it's the same as map, but I think collect makes the code more understandable.
select(&:even?).map()
actually looks better, after seeing it below.
Ruby 2.7 introduced filter_map which pretty much achieves what you want (map + compact):
some_array.filter_map { |x| x * 3 if x % 2 == 0 }
You can read more about it here.
Like Pedro mentioned, you can fuse together the chained calls to Enumerable#select and Enumerable#map, avoiding a traversal over the selected elements. This is true because Enumerable#select is a specialization of fold or inject. I posted a hasty introduction to the topic at the Ruby subreddit.
Manually fusing Array transformations can be tedious, so maybe someone could play with Robert Gamble's comprehend implementation to make this select/map pattern prettier.
Something like this:
def lazy(collection, &blk)
collection.map{|x| blk.call(x)}.compact
end
Call it:
lazy (1..6){|x| x * 3 if x.even?}
Which returns:
=> [6, 12, 18]
Another solution but perhaps not the best one
some_array.flat_map {|x| x % 2 == 0 ? [x * 3] : [] }
or
some_array.each_with_object([]) {|x, list| x % 2 == 0 ? list.push(x * 3) : nil }
This is one way to approach this:
c = -> x do $*.clear
if x['if'] && x[0] != 'f' .
y = x[0...x.index('for')]
x = x[x.index('for')..-1]
(x.insert(x.index(x.split[3]) + x.split[3].length, " do $* << #{y}")
x.insert(x.length, "end; $*")
eval(x)
$*)
elsif x['if'] && x[0] == 'f'
(x.insert(x.index(x.split[3]) + x.split[3].length, " do $* << x")
x.insert(x.length, "end; $*")
eval(x)
$*)
elsif !x['if'] && x[0] != 'f'
y = x[0...x.index('for')]
x = x[x.index('for')..-1]
(x.insert(x.index(x.split[3]) + x.split[3].length, " do $* << #{y}")
x.insert(x.length, "end; $*")
eval(x)
$*)
else
eval(x.split[3]).to_a
end
end
so basically we are converting a string to proper ruby syntax for loop
then we can use python syntax in a string to do:
c['for x in 1..10']
c['for x in 1..10 if x.even?']
c['x**2 for x in 1..10 if x.even?']
c['x**2 for x in 1..10']
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# [2, 4, 6, 8, 10]
# [4, 16, 36, 64, 100]
# [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
or if you don't like the way the string looks or having to use a lambda we could forego the attempt to mirror python syntax and do something like this:
S = [for x in 0...9 do $* << x*2 if x.even? end, $*][1]
# [0, 4, 8, 12, 16]
https://rubygems.org/gems/ruby_list_comprehension
shameless plug for my Ruby List Comprehension gem to allow idiomatic Ruby list comprehensions
$l[for x in 1..10 do x + 2 end] #=> [3, 4, 5 ...]
I think the most list comprehension-esque would be the following:
some_array.select{ |x| x * 3 if x % 2 == 0 }
Since Ruby allows us to place the conditional after the expression, we get syntax similar to the Python version of the list comprehension. Also, since the select method does not include anything that equates to false, all nil values are removed from the resultant list and no call to compact is necessary as would be the case if we had used map or collect instead.

Resources