Counting integers in array from 1 to 100 in increments of 10 - ruby

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.

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

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.

(0..100).step(10).each_cons(2).map do |min, max|
ar.count { |number| number.between?(min.next, max) }
end

Related

How to sort by value in hash?

So I made a random number generator which is supposed to count the frequency of the numbers and display them in sorted order. I'm trying to use .sort but I can't figure out where to put it to sort the values of the hash in order. What I have so far:
MIN_VALUE = 1
count = 0
puts "Enter a number of random integers to generate"
resp = gets.to_i
p "number of integers generated is #{resp}"
puts "Now enter the maximum value the integers can be"
max_value = gets.to_i
p "max value is set to #{max_value}"
size = Array.new(resp)
while (count < resp)
int_value = (rand(MIN_VALUE..max_value))
size.push(int_value)
count = count + 1
end
puts size
freq = Hash.new(0)
size.each { |x| freq[x] += 1 }
freq.map{ |key, value| "#{key}x#{value}" }.join(',')
freq.each do |key,value|
puts "Frequency of #{key} is: #{value}"
end
Any help is greatly appreciated!
More or less the same soup, generating random numbers in an Integer#times loop:
upper_number = 10
sample_size = 100
freq = Hash.new(0) # initializing the hash with a default value of zero, for counting
sample_size.times { freq[rand((1..upper_number))] += 1 } # here the loop generating and counting
freq #=> {5=>13, 7=>10, 1=>11, 2=>13, 8=>13, 9=>6, 3=>6, 6=>9, 10=>11, 4=>8}
Then you can sort by frequencies (reverse order: -v) and by sample value (k), [-v, k]:
freq.sort_by{ |k, v| [-v, k] }.to_h #=> {2=>13, 5=>13, 8=>13, 1=>11, 10=>11, 7=>10, 6=>9, 4=>8, 3=>6, 9=>6} # for this run
freq.sum { |_, v| v} #=> 100 # of course
Suppose
arr = [4, 1, 3, 4, 2, 5, 1, 3, 4, 3, 4]
You can use the form of Hash::new that takes an argument, called its default value (which often, as here, is zero), to obtain the frequency of the elements of arr:
freq = arr.each_with_object(Hash.new(0)) { |n,h| h[n] += 1 }
#=> {4=>4, 1=>2, 3=>3, 2=>1, 5=>1}
We see that
freq[1]
#=> 2
freq[99]
#=> 0
The second result follows because freq was defined to have a default value of 0. All that means is that if freq does not have a key k, freq[k] returns zero (and that does not alter freq).
Here are solutions to two possible interpretations of your question. Both use the method Enumerable#sort_by.
Sort the unique values of arr by decreasing frequency
freq.sort_by { |_,v| -v }.map(&:first)
#=> [4, 3, 1, 2, 5]
Sort the values of arr by decreasing frequency
arr.sort_by { |n| -freq[n] }
#=> [4, 4, 4, 4, 3, 3, 3, 1, 1, 2, 5]
Replace -v and -freq[n] with v and freq[n] to sort by increasing frequency.
I've used the local variable _ to represent the keys in the first interpretation to signify that it is not used in the block calculation. This is common practice.

Predict winning number depending on results?

I want to generate the most probable number depending on the latest lottery results I have on a CSV.
I have this script:
h = Hash.new
f = File.open('numbers.csv', "r")
f.each_line { |line|
numbers = line.split
numbers.each { |w|
if h.has_key?(w)
h[w] = h[w] + 1
else
h[w] = 1
end
}
}
# sorteamos el hash por valor, y lo pintamos segĂșn la concurrencia
h.sort{|a,b| a[1]<=>b[1]}.each { |elem|
puts "\"#{elem[0]}\" tiene #{elem[1]} concurrencia"
}
That will tell me which numbers have the most ocurrencies.
I want to "sample" a number depending on these results that has the most probability.
How can I achieve this? Thanks!
I don't think Ruby has a built-in elegant way of doing this. You can treat your hash as a bunch of bins, where the number of occurrences of each number is the bin size. Then you can calculate the total bin width, get a random sample, and iterate to find out which bin the sample lands in.
def weighted_sample h
weight = h.values.reduce(:+)
sample = rand weight
h.each do |n, w|
return n if sample < w
sample -= w
end
end
Array.new(10) { weighted_sample({1 => 8, 2 => 4, 3 => 2}) }
# [2, 2, 1, 1, 1, 3, 1, 1, 1, 1]
Tip: there's a much nicer way to build that hash
h = Hash.new 0
# ...
h[w] += 1

Checking to see if 2 numbers in array sum to 0 in Ruby

I've been going at this problem for a few hours, and I can't see why I can't get it to run properly. The end game to this method is having 2 numbers in an array equaling zero when added together. Here is my code:
def two_sums(nums)
i = 0
j = -1
while i < nums.count
num_1 = nums[i]
while j < nums.count
num_2 = nums[j]
if num_1 + num_2 == 0
return "There are 2 numbers that sum to zero & they are #{num_1} and #{num_2}."
else
return "Nothing adds to zero."
end
end
i += 1
j -= 1
end
end
The problem I'm having is unless the first and last number in the array are the positive and negative of the same number, this will always return false.
For example, if I had an array that was [1, 4, 6, -1, 10], it should come back true. I'm sure my 2 while statement is the cause of this, but I can't think of a way to fix it. If someone could point me in the right direction, that would be helpful.
You can find the first pair that adds up to 0 like this:
nums.combination(2).find { |x, y| x + y == 0 }
#=> returns the first matching pair or nil
Or if you want to select all pairs that add up to 0:
nums.combination(2).select { |x, y| x + y == 0 }
#=> returns all matching pairs or an empty array
Therefore you can implement your method like this:
def two_sums(nums)
pair = nums.combination(2).find { |x, y| x + y == 0 }
if pair
"There are 2 numbers that sum to zero & they are #{pair.first} and #{pair.last}."
else
"Nothing adds to zero."
end
end
Or if you want to find all pairs:
def two_sums(nums)
pairs = nums.combination(2).select { |x, y| x + y == 0 }
if pairs.empty?
"Nothing adds to zero."
else
"The following pairs sum to zero: #{pairs}..."
end
end
Here's another way:
Code
def sum_to_zero(arr)
arr.group_by { |e| e.abs }
.values
.select { |a| (a.size > 1 && a.first == 0) || a.uniq.size > 1 }
end
Examples
sum_to_zero [1, 4, 6, -1, 10] #=> [[1, -1]]
sum_to_zero [1, 4, 1, -2, 10] #=> []
sum_to_zero [1, 0, 4, 1, 0, -1] #=> [[1, 1, -1], [0, 0]]
This method is relatively fast. Let's try it with an array of 200,000 elements, each a random number between -500,000 and 500,000.
require 'time'
t = Time.now
arr = Array.new(200_000) { rand(1_000_001) - 500_000 }
arr.size #=> 200000
sum_to_zero(arr).size #=> 16439
Time.now - t
#=> 0.23 (seconds)
sum_to_zero(arr).first(6)
#=> [[-98747, 98747],
# [157848, -157848],
# [-459650, 459650],
# [176655, 176655, -176655],
# [282101, -282101],
# [100886, 100886, -100886]]
If you wish to group the non-negative and negative values that sum to zero:
sum_to_zero(arr).map { |a| a.partition { |e| e >= 0 } }.first(6)
#=> [[[98747], [-98747]],
# [[157848], [-157848]],
# [[459650], [-459650]],
# [[176655, 176655], [-176655]],
# [[282101], [-282101]],
# [[100886, 100886], [-100886]]]
If you only want a single value for each group (a non-negative value, say):
sum_to_zero(arr).map { |a| a.first.abs }.first(6)
#=> [98747, 157848, 459650, 176655, 282101, 100886]
I think the most Ruby way would be:
nums.combination(2).any? { |x,y| (x+y).zero? }
Here's a way that should work well for large arrays. The methods above which go through every possible combination of two numbers are perfectly fine for small cases but will be very slow and memory hungry for arrays with lots of elements.
def two_sums nums
h = Hash.new
nums.each do |n|
return true if h[-n]
h[n] = true
end
false
end
Well, given it's tagged as #ruby, here's the most "ruby way" I could think of tackling this problem:
def two_sums(arr)
numbers = arr.combination(2).select { |a| a.reduce(:+) == 0 }.flatten
if numbers.empty?
"Nothing adds to zero."
else
"There are 2 numbers that sum to zero & they are #{numbers.first} and #{numbers.last}."
end
end
array.combination(2).select{|x|x[0] + x[1] == 0}

How to split an array into sub-arrays based on integer values

I need to know how you break an array into sub-arrays based on the value of the integers in the array. What I'm trying to do is take a large array and break it into 1-10, 11-20, 21-30...etc and I need to then be able to count those sub arrays so I have numbers that are like "7 integers between 1-10, 6 integers between 11-20, 12 integers between 21-30."
I've got a single line random number generator that will give me my array like the following:
rand_num = (Array.new(200) {(1..100).to_a[rand(100)]})
This gives me my array of 200 hundred random numbers between 1 and 100 and now I need to be able to split them apart according to value and tell how much is in each one.
Then I need it to display those numbers. I've searched everywhere and I want to say you do this with .partition, but I just can't get it to work.
If your buckets really are that simple then you could use group_by like this:
array.group_by { |n| (n - 1) / 10 }
That will give you Hash like this:
{0=>[1, 2, 3, ...], 1=>[11, 12, 13, ...], ...}
then you just throw in a sort_by to force a nice ordering and a map to summarize the results:
array.group_by { |n| (n - 1) / 10 }.
sort_by { |k, v| k }.
map { |n, a| [10 * n + 1 .. 10 * (n + 1), a.length] }
For example:
# The %7 is just an easy way to get a non-uniform set.
>> (1..100).select { |n| n % 7 == 0 }
=> [7, 14, 21, 28, 35, 42, 49, 56, 63, 70, 77, 84, 91, 98]
>> (1..100).select { |n| n % 7 == 0 }.sort_by { |k, v| k }.group_by { |n| (n - 1) / 10 }.map { |n, a| [10 * n + 1 .. 10 * (n + 1), a.length] }
=> [[1..10, 1], [11..20, 1], [21..30, 2], [31..40, 1], [41..50, 2], [51..60, 1], [61..70, 2], [71..80, 1], [81..90, 1], [91..100, 2]]
results = {}
rand_num.each do |x|
if x%10 == 0
results[x/10 - 1] = [] unless results.key?(x/10 - 1)
results[x/10 - 1] << x
else
results[x/10] = [] unless results.key?(x/10)
results[x/10] << x
end
end
Now in key 0 you have numbers between 1-10, in key 1 between 11-20 etc. p.s. I didn't run this code anywhere so it may have bugs ;)

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 :)

Resources