Reputation: 137
a = Array.new(200) { rand(1..100) }.sort!
puts a.count{ |a| (a > 0 && a < 11) }
puts a.count{ |b| (b > 10 && b < 21) }
puts a.count{ |c| (c > 20 && c < 31) }
puts a.inspect
So I can just repeat this all the way to 100 which works but I'm looking for a short cut to hopefully count all the digits pairs with the single line at the top(Add onto the single line). Hopefully each 10 (1-10, 11-20, etc) has a different variable that I can call later on. Or at-least be able to convert it.
make variables like
b = a.count{ |c| (c > 20 && c < 31) }
so later i could use it to make a string like
puts "#" * b
so the end result of it all will look like below
1-10 #########################
11-20 ##############################
21-30 ######################
each # representing how much 1-10 there were.
Upvotes: 1
Views: 913
Reputation: 198324
counts = 10.times.map { |i| (i + 1)...(i + 11) }.map { |range|
a.count { |x| range.include? x }
}
counts[0]
# => 17 (number of numbers in 1...11)
counts[1]
# => 20 (number of numbers in 11...21)
counts[2]
# => 22 (number of numbers in 21...31)
# ...
EDIT: Or even easier, by exploiting a simple mathematical property:
counts = a.group_by { |x| (x - 1) / 10 }.map { |k, v| v.count }
Hopefully each 10 (1-10, 11-20, etc) has a different variable that I can call later on.
Why would you want different variables when you can have an array?
EDIT2: Whole program, in 1-4 lines:
array = 200.times.map { rand(1..100) }.sort
array.group_by { |x| (x - 1) / 10 }.each do |k, v|
puts "%2d-%2d %s" % [k * 10 + 1, k * 10 + 10, "#" * v.count]
end
Translation: Do two hundred iterations, and construct an array, such that each element is a random number between 1 and 100. Then group the array by the result of division by 10 (adjusting by 1 so we don't get ranges of 0-9, 10-19...); iterating on the hash containing the division result and items, print the bounds (reconstructing the start and the end from the division result) and also a number of hashes corresponding to the number of items in each group.
EDIT3: As Stefan notes, we can use chunk
because the array is sorted, for a bit of a speedup. group_by
above doesn't care about the array being sorted. You can simply replace group_by
with chunk
even though they return different types, simply because iterating on hashes works the same way as iterating on array of two-element arrays.
array = 200.times.map { rand(1..100) }.sort
array.chunk { |x| (x - 1) / 10 }.each do |k, v|
puts "%2d-%2d %s" % [k * 10 + 1, k * 10 + 10, "#" * v.count]
end
Upvotes: 3
Reputation: 110675
I suggest using a counting hash.
(a = (Array.new(20){|x| x=(rand(1..100)) })).sort!
#=> [3, 12, 17, 17, 20, 31, 32, 43, 47, 50, 62, 65, 70, 83, 87, 89, 92, 94, 97, 98]
g = a.each_with_object(Hash.new(0)) do |n,h|
interval_first = 1+10*((n-1)/10)
h[interval_first..interval_first+9] += 1
end
#=> {1..10=>1, 11..20=>4, 31..40=>2, 41..50=>3, 61..70=>3, 81..90=>3, 91..100=>4}
Notice that
g[21..30] #=> 0
g[51..60] #=> 0
even though g
does not have keys 21..30
and 51..60
.
If intervals with values of zero are to be included in g
, this is one way that could be done:
g = 10.times.map { |i| [1+10*i..10+10*i, 0] }.to_h
#=> {1..10=>0, 11..20=>0, 21..30=>0, 31..40=>0, 41..50=>0, 51..60=>0,
# 61..70=>0, 71..80=>0, 81..90=>0, 91..100=>0}
a.each_with_object(g) do |n,h|
interval_first = 1+10*((n-1)/10)
h[interval_first..interval_first+9] += 1
end
# => {1..10=>1, 11..20=>4, 21..30=>0, 31..40=>2, 41..50=>3, 51..60=>0,
# 61..70=>3, 71..80=>0, 81..90=>3, 91..100=>4}
See Hash::new.
Note that pre-sorting the array of random numbers is of no benefit with this method. That probably holds true with most approaches one might consider.
Upvotes: 1
Reputation: 36101
(0..100).step(10).each_cons(2).map do |min, max|
ar.count { |number| number.between?(min.next, max) }
end
Upvotes: 0