I get the desired output but the interpreter throws an ArgumentError-bad value for range ?
Q)Given an array of integers, for each integer output all integers from 1 to that integer; e.g. if the integer was 5, you would output 1, 2, 3, 4, 5.
Solution:
numbers = [7, 3, 5, 2, 1, 8, 4]
counter = 0
loop do
num = numbers[counter]
(1..num).each do |ele|
puts ele
end
counter += 1
end
I'll let someone else explain why your code is broken, except to say that unless this is a classroom exercise (in which case ask your instructor what the point is), the code is not really idiomatic Ruby. Aside from being more complicated than it needs to be, non-idiomatic Ruby is often harder to debug. One of the following examples will do the right thing when using Ruby 3.0.1, and both are much shorter and less error-prone that manually iterating:
# if you just want to print each item
numbers = [7, 3, 5, 2, 1, 8, 4]
numbers.each { puts _1 }
# if you want to print each slice of length n
numbers.each_index do
next unless _1 > 0
p numbers.slice 0, _1
end
If you need your output in a specific format, that wasn't defined in your original question. Both of these options can be modified to suit whatever output format you're looking for.
Related
I am looking to print odd numbers in an array. I have this:
numbers = []
puts "Please enter 10 numbers, one at a time."
10.times do
puts "Please enter a number"
numbers << gets.chomp.to_i
if numbers % 3 == 0
p numbers
end
numbers = numbers + 1
end
puts "Here are the numbers you selected"
p numbers
When I type in a number, I get the following:
undefined method `%' for [1]:Array
(repl):6:in `block in <main>'
Any idea as to what is happening?
Checking values modulo 3 won't work to correctly identify odd numbers. However, Ruby has a built-in method Integer#odd?. Combine this with the Array#select method, and you can quickly pick off array elements that are odd once you've read them in.
a = (1..10).to_a # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
p a.select(&:odd?) # [1, 3, 5, 7, 9]
If you insist on using the modulo operator, you would check for x % 2 == 1 to check integer x for oddness:
p a.select { |x| x % 2 == 1 } # [1, 3, 5, 7, 9] again, but less efficiently
The modulo method does not work with an array as the receiver, which is what you attempted to do. That's what the error message is telling you.
Odd number is a number that when divided by two, leaves a remainder.
So in Ruby it looks like number % 2 != 0. Why do you decide to use % 3?
In your code numbers is Array, but you can use % only to numbers.
And you don't need it because in Ruby Integer has built-in method odd?. It returns true if number is odd.
You can use method .find_all or .select to your Array. Read here.
Also you use numbers = numbers + 1. It's better to write numbers += 1, it's the same. But you don't need it when use method .times. Read here.
By the way, you don't need use .chomp if your variable will be Integer, just use .to_i
So it's better to use code like this:
numbers = []
10.times do
puts 'Enter a number'
number = gets.to_i
numbers << number
end
puts "Here your odd numbers: #{numbers.find_all(&:odd?)}"
So there is an infinte loop here, but I'm not seeing it.
# Return an array that doubles each number
numbers = [1, 2, 3, 4]
numbers.each do |number|
numbers << number * 2
end
puts numbers
I understand there are shorter ways to do this, but I am learning so it's all written out more explicitly.
You're adding elements to an array while iterating over that array. It's therefore impossible to reach the end.
What you need to do is use the map function:
numbers.map! do |n|
n * 2
end
That updates each entry in place with its value times two.
If you're looking to add on a single set of doubled numbers:
numbers += numbers.map do |n|
n * 2
end
That adds on a copy of the array that's been doubled.
Edit: Instead of using map, for academic illustration purposes, you can try using a copy with dup:
numbers.dup.each do |n|
numbers << n * 2
end
You can also iterate over it sequentially:
numbers.each_index do |i|
numbers << numbers[i] * 2
end
These are all far less efficient and are much harder to read than the map version.
You cant see the process since this infinity lasts forever and never reaches your puts numbers statement. Thats why you cant see it in the console.
Try something like:
numbers = [1, 2, 3, 4]
numbers.each do |number|
numbers << number * 2
puts numbers
end
To see your pc going mad :)
by pushing the doubled value in the array you are increasing the array size each time by 1. hence infinite loop is occurring. I think what you really want to do is
numbers.each do |num|
puts num *2
end
Return an array that doubles each number
Assuming you don't want to use map, you can use Enumerable#each_with_object:
numbers = [1, 2, 3, 4]
numbers.each_with_object([]) { |n, o| o << n + n }
#=> [2, 4, 6, 8]
Since nobody mentioned the obvious answer, here it is :
numbers = [1, 2, 3, 4]
double_numbers = []
numbers.each do |number|
double_numbers << number * 2
end
p double_numbers
# [2, 4, 6, 8]
This would be the way to do it if you didn't know about map or map!. Note that you iterate on one array and create another one in order to avoid messing with the each loop.
This works in Ruby:
a = 4..Float::INFINITY
p a.take(4) #=> [4,5,6,7]
But I was wondering if it's possible to do something similar where the range would be from negative infinity up to a certain number, say 4, and have a method that will take the last, say 6 elements from that sequence, which would be [-1,0,1,2,3,4].
Getting the last N numbers from a range -infinity..4 is the same of selecting a range of 4..(4-N).
4.downto(4-5).to_a
# => [4, 3, 2, 1, 0, -1]
You can package it as a custom method
def lastn(from, n)
from.downto(from-n).to_a
end
How about the last method?
a.last(6)
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Turning long fixed number to array Ruby
Well, I have to iterate over the digits of a integer in Ruby. Right now I was just splitting it up into an array, and then iterating over that. However I was wondering if there was a faster way to do this?
The shortest solution probably is:
1234.to_s.chars.map(&:to_i)
#=> [1, 2, 3, 4]
A more orthodox mathematical approach:
class Integer
def digits(base: 10)
quotient, remainder = divmod(base)
quotient == 0 ? [remainder] : [*quotient.digits(base: base), remainder]
end
end
0.digits #=> [0]
1234.digits #=> [1, 2, 3, 4]
0x3f.digits(base: 16) #=> [3, 15]
You can use the old trick of modulus/divide by 10, but this won't be measurably faster unless you have huge numbers, and it will give the digits to you backwards:
i = 12345
while i > 0
digit = i % 10
i /= 10
puts digit
end
Output:
5
4
3
2
1
split=->(x, y=[]) {x < 10 ? y.unshift(x) : split.(x/10, y.unshift(x%10))}
split.(1000) #=> [1,0,0,0]
split.(1234) #=> [1,2,3,4]
Ruby has divmod, which will calculate both x%10and x/10 in one go:
class Integer
def split_digits
return [0] if zero?
res = []
quotient = self.abs #take care of negative integers
until quotient.zero? do
quotient, modulus = quotient.divmod(10) #one go!
res.unshift(modulus) #put the new value on the first place, shifting all other values
end
res # done
end
end
p 135.split_digits #=>[1, 3, 5]
For things like Project Euler, where speed is of some importance, this is nice to have. Defining it on Integer causes it to be available on Bignum too.
I like to use enumerators for this purpose:
class Integer
def digits
to_s.each_char.lazy.map(&:to_i)
end
end
This gives you access to all the good Enumerator stuff:
num = 1234567890
# use each to iterate over the digits
num.digits.each do |digit|
p digit
end
# make them into an array
p num.digits.to_a # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
# or take only some digits
p num.digits.take(5) # => [1, 2, 3, 4, 5]
# ...
Try mod by 10 (will give you the last digit), then divide by 10 (will give you the rest of digits), repeat this until you're down to the final digit. Of course, you'll have to reverse the order if you want to go through the digits from left to right.
Summary: The basic question here was, I've discovered, whether you can pass a code block to a Ruby array which will actually reduce the contents of that array down to another array, not to a single value (the way inject does). The short answer is "no".
I'm accepting the answer that says this. Thanks to Squeegy for a great looping strategy to get streaks out of an array.
The Challenge: To reduce an array's elements without looping through it explicitly.
The Input: All integers from -10 to 10 (except 0) ordered randomly.
The Desired Output: An array representing streaks of positive or negative numbers. For instance, a -3 represents three consecutive negative numbers. A 2 represents two consecutive positive numbers.
Sample script:
original_array = (-10..10).to_a.sort{rand(3)-1}
original_array.reject!{|i| i == 0} # remove zero
streaks = (-1..1).to_a # this is a placeholder.
# The streaks array will contain the output.
# Your code goes here, hopefully without looping through the array
puts "Original Array:"
puts original_array.join(",")
puts "Streaks:"
puts streaks.join(",")
puts "Streaks Sum:"
puts streaks.inject{|sum,n| sum + n}
Sample outputs:
Original Array:
3,-4,-6,1,-10,-5,7,-8,9,-3,-7,8,10,4,2,5,-2,6,-1,-9
Streaks:
1,-2,1,-2,1,-1,1,-2,5,-1,1,-2
Streaks Sum:
0
Original Array:
-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,1,2,3,4,5,6,7,8,9,10
Streaks:
-10,10
Streaks Sum:
0
Note a few things:
The streaks array has alternating positive and negative values.
The sum of the elements streaks array is always 0 (as is the sum of the original).
The sum of the absolute values of the streak array is always 20.
Hope that's clear!
Edit: I do realize that such constructs as reject! are actually looping through the array in the background. I'm not excluding looping because I'm a mean person. Just looking to learn about the language. If explicit iteration is necessary, that's fine.
Well, here's a one-line version, if that pleases you more:
streaks = original_array.inject([]) {|a,x| (a.empty? || x * a[-1] < 0 ? a << 0 : a)[-1] += x <=> 0; a}
And if even inject is too loopy for you, here's a really silly way:
streaks = eval "[#{original_array.join(",").gsub(/((\-\d+,?)+|(\d+,?)+)/) {($1[0..0] == "-" ? "-" : "") + $1.split(/,/).size.to_s + ","}}]"
But I think it's pretty clear that you're better off with something much more straightforward:
streaks = []
original_array.each do |x|
xsign = (x <=> 0)
if streaks.empty? || x * streaks[-1] < 0
streaks << xsign
else
streaks[-1] += xsign
end
end
In addition to being much easier to understand and maintain, the "loop" version runs in about two-thirds the time of the inject version, and about a sixth of the time of the eval/regexp one.
PS: Here's one more potentially interesting version:
a = [[]]
original_array.each do |x|
a << [] if x * (a[-1][-1] || 0) < 0
a[-1] << x
end
streaks = a.map {|aa| (aa.first <=> 0) * aa.size}
This uses two passes, first building an array of streak arrays, then converting the array of arrays to an array of signed sizes. In Ruby 1.8.5, this is actually slightly faster than the inject version above (though in Ruby 1.9 it's a little slower), but the boring loop is still the fastest.
new_array = original_array.dup
<Squeegy's answer, using new_array>
Ta da! No looping through the original array. Although inside dup it's a MEMCPY, which I suppose might be considered a loop at the assembler level?
http://www.ruby-doc.org/doxygen/1.8.4/array_8c-source.html
EDIT: ;)
original_array.each do |num|
if streaks.size == 0
streaks << num
else
if !((streaks[-1] > 0) ^ (num > 0))
streaks[-1] += 1
else
streaks << (num > 0 ? 1 : -1)
end
end
end
The magic here is the ^ xor operator.
true ^ false #=> true
true ^ true #=> false
false ^ false #=> false
So if the last number in the array is on the same side of zero as the number being processed, then add it to the streak, otherwise add it to the streaks array to start a new streak. Note that sine true ^ true returns false we have to negate the whole expression.
Since Ruby 1.9 there's a much simpler way to solve this problem:
original_array.chunk{|x| x <=> 0 }.map{|a,b| a * b.size }
Enumerable.chunk will group all consecutive elements of an array together by the output of a block:
>> original_array.chunk{|x| x <=> 0 }
=> [[1, [3]], [-1, [-4, -6]], [1, [1]], [-1, [-10, -5]], [1, [7]], [-1, [-8]], [1, [9]], [-1, [-3, -7]], [1, [8, 10, 4, 2, 5]], [-1, [-2]], [1, [6]], [-1, [-1, -9]]]
This is almost exactly what OP asks for, except the resulting groups need to be counted up to get the final streaks array.
More string abuse, a la Glenn McDonald, only different:
runs = original_array.map do |e|
if e < 0
'-'
else
'+'
end
end.join.scan(/-+|\++/).map do |t|
"#{t[0..0]}#{t.length}".to_i
end
p original_array
p runs
# => [2, 6, -4, 9, -8, -3, 1, 10, 5, -7, -1, 8, 7, -2, 4, 3, -5, -9, -10, -6]
# => [2, -1, 1, -2, 3, -2, 2, -1, 2, -4]