Related
numbers = [1, 2, 3, 4, 5]
for num in numbers
puts "insert q "
qanswer1 = gets.chomp.to_i
puts "insert 2nd q"
qanswer2 = gets.chomp.to_i
end
This code will repeat the questions 5 times. How do I retrieve the user-inputted data? I'm trying to calculate the total sum of all 10 responses and the index in which the sum of each pair was the highest.
nbr_pairs = 5
def ask(str)
print "#{str}: "
gets.to_i
end
arr = nbr_pairs.times.map { [ask("insert q"), ask("insert 2nd q")] }
#=> [[7, 3], [8, 6], [2, 9], [4, 6], [8, 3]]
Sum of all 10 replies
arr.flatten.sum
#=> 56
Index of largest sum of pairs
nbr_pairs.times.max_by { |i| arr[i].sum }
#=> 1 (8+6 = 14)
See Integer#times, Array#flatten, Enumerable#max_by and Array#sum.
I tried to make a solution as close as possible to yours while still producing the desired results :
numbers = [0,1,2,3,4]
pairs = Array.new(numbers.size, [])
numbers.each do |number|
pairs[number] = []
puts "q 1:"
pairs[number] << gets.to_i
puts "q 2:"
pairs[number] << gets.to_i
end
To get the pair with the max value:
max_value = pairs.max_by(&:sum)
To get the sum of all pairs:
sum_of_all_responses = pairs.flatten.sum
To get the index of the pair with the highest value:
pairs.index(max_value)
If you don't need to store all the data, you could just do calculations on the fly.
First move the input request to a method which returns the pair of value n an array:
def ask
puts "insert q "
qanswer1 = gets.to_i
puts "insert 2nd q"
qanswer2 = gets.to_i
[qanswer1, qanswer2]
end
Then set up variables
big_sum = 0
best_input = 0
best_input_q_number = nil
Finally loop as you did doing the math:
numbers = [1,2,3,4,5]
for n in numbers
# (1..5).each do |n| # this is more Ruby-ish
p qanswers = ask # p for debug
qanswers_sum = qanswers.sum
big_sum += qanswers_sum
if qanswers_sum > best_input
best_input = qanswers_sum # or qanswers if you want to keep the pairs
best_input_q_number = n
end
end
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
I need to check whether the sum of any 2 elements of an array equals to the given number. This is what I came up with, but it doesn't seem to do the comparison
def sum_comparison(int_array, x)
n = int_array.length
(0..n).each do |i|
(1..n).each do |j|
if ((int_array[i].to_i + int_array[j].to_i) == x)
return true
else
return false
end
end
end
end
Your solution seems overly complicated and strongly influenced by the programming style of low-level procedural languages like C. One apparent problem is that you write
n = int_array.length
(0..n).each do |i|
# use int_array[i].to_i inside the loop
end
Now inside the each loop, you will get the numbers i = 0, 1, 2, ..., n, for example for int_array = [3,4,5] you get i = 0, 1, 2, 3. Notice that there are four elements, because you started counting at zero (this is called an off by one error). This will eventually lead to an array access at n, which is one beyond the end of the array. This will again result in a nil coming back, which is probably why you use to_i to convert that back to an integer, because otherwise you would get a TypeError: nil can't be coerced into Fixnum whend doing the addition. What you probably wanted instead was simply:
int_array.each do |i|
# use i inside the loop
end
For the example array [3,4,5] this would actually result in i = 3, 4, 5. To get the combinations of an array in a more Ruby way, you can for example use Array#combination. Likewise, you can use Array#any? to detect if any of the combinations satisfy the specified condition:
def sum_comparison(array, x)
array.combination(2).any? do |a, b|
a + b == x
end
end
When your function compare first element, it's immediately returns false. You need to return only true when iterating and return false at the end if nothing were found, to avoid this issue:
def sum_comparison(int_array, x)
n = int_array.size
(0...n).each do |i|
(1...n).each do |j|
if (int_array[i].to_i + int_array[j].to_i) == x
return true
end
end
end
false
end
To simplify this you can use permutation or combination and any? methods as #p11y suggests. To get founded elements you could use find or detect.
def sum_comparison(a, x)
a.combination(2).any? { |i, j| i + j == x }
end
a.combination(2).detect { |i, j| i + j == x }
# sum_comparison([1,2,3, 4], 6) => [2, 4]
Using an enumerator:
#!/usr/bin/env ruby
def sum_comparison(int_array, x)
enum = int_array.to_enum
loop do
n = enum.next
enum.peek_values.each do |m|
return true if (n + m) == x
end
end
false
end
puts sum_comparison([1, 2, 3, 4], 5)
Output:
true
Problem
Your method is equivalent to:
def sum_comparison(int_array, x)
return int_array[0].to_i + int_array[1].to_i == x
end
Therefore,
int_array = [1,2,4,16,32,7,5,7,8,22,28]
sum_comparison(int_array, 3) #=> true, just lucky!
sum_comparison(int_array, 6) #=> false, wrong!
Alternative
Here is a relatively efficient implemention, certainly far more efficient than using Enumerable#combination.
Code
def sum_comparison(int_array, x)
sorted = int_array.sort
smallest = sorted.first
sorted_stub = sorted.take_while { |e| e+smallest <= x }
p "sorted_stub = #{sorted_stub}"
return false if sorted_stub.size < 2
loop do
return false if sorted_stub.size < 2
v = sorted_stub.shift
found = sorted_stub.find { |e| v+e >= x }
return true if found && v+found == x
end
false
end
Examples
sum_comparison([7,16,4,12,-2,5,8], 3)
# "sorted_stub = [-2, 4, 5]"
#=> true
sum_comparison([7,16,4,12,-2,5,8], 7)
# "sorted_stub = [-2, 4, 5, 7, 8]"
#=> false
sum_comparison([7,16,4,22,18,12,2,41,5,8,17,31], 9)
# "sorted_stub = [2, 4, 5, 7]"
#=> true
Notes
The line p "sorted_stub = #{sorted_stub}" is included merely to display the array sorted_stub in the examples.
If e+smallest > x for any elements f and g in sorted for which g >= e and f < g, f+g >= e+smallest > x. Ergo, sorted_stub.last is the largest value in sorted that need be considered.
For a given value v, the line found = sorted_stub.find { |e| v+e >= x } stops the search for a second value e for which v+e = x as soon as it finds e such that v+e >= x. The next line then determines if a match has been found.
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}
Maybe it's just my lack of abilities to find stuff here that is the problem, but I can't find anything about how to create multidimensional arrays in Ruby.
Could someone please give me an example on how to do it?
Strictly speaking it is not possible to create multi dimensional arrays in Ruby. But it is possible to put an array in another array, which is almost the same as a multi dimensional array.
This is how you could create a 2D array in Ruby:
a = [[1,2,3], [4,5,6], [7,8,9]]
As stated in the comments, you could also use NArray which is a Ruby numerical array library:
require 'narray'
b = NArray[ [1,2,3], [4,5,6], [7,8,9] ]
Use a[i][j] to access the elements of the array. Basically a[i] returns the 'sub array' stored on position i of a and thus a[i][j] returns element number j from the array that is stored on position i.
you can pass a block to Array.new
Array.new(n) {Array.new(n,default_value)}
the value that returns the block will be the value of each index of the first array,
so..
Array.new(2) {Array.new(2,5)} #=> [[5,5],[5,5]]
and you can access this array using array[x][y]
also for second Array instantiation, you can pass a block as default value too. so
Array.new(2) { Array.new(3) { |index| index ** 2} } #=> [[0, 1, 4], [0, 1, 4]]
Just a clarification:
arr = Array.new(2) {Array.new(2,5)} #=> [[5,5],[5,5]]
is not at all the same as:
arr = Array.new(2, Array.new(2, 5))
in the later case, try:
arr[0][0] = 99
and this is what you got:
[[99,5], [99,5]]
There are two ways to initialize multi array (size of 2).
All the another answers show examples with a default value.
Declare each of sub-array (you can do it in a runtime):
multi = []
multi[0] = []
multi[1] = []
or declare size of a parent array when initializing:
multi = Array.new(2) { Array.new }
Usage example:
multi[0][0] = 'a'
multi[0][1] = 'b'
multi[1][0] = 'c'
multi[1][1] = 'd'
p multi # [["a", "b"], ["c", "d"]]
p multi[1][0] # "c"
So you can wrap the first way and use it like this:
#multi = []
def multi(x, y, value)
#multi[x] ||= []
#multi[x][y] = value
end
multi(0, 0, 'a')
multi(0, 1, 'b')
multi(1, 0, 'c')
multi(1, 1, 'd')
p #multi # [["a", "b"], ["c", "d"]]
p #multi[1][0] # "c"
The method given above don't works.
n = 10
arr = Array.new(n, Array.new(n, Array.new(n,0.0)))
arr[0][1][2] += 1
puts arr[0][2][2]
is equivalent to
n = 10
a = Array.new(n,0.0)
b = Array.new(n,a)
arr = Array.new(n, b)
arr[0][1][2] += 1
puts arr[0][2][2]
and will print 1.0, not 0.0, because we are modifiyng array a and printing the element of array a.
Actually this is much quicker than the block method given above:
arr = Array.new(n, Array.new(n, Array.new(n,0.0)))
arr[0][1][2] += 1
I had to reproduce PHP-style multidimensional array in Ruby recently. Here is what I did:
# Produce PHP-style multidimensional array.
#
# Example
#
# arr = Marray.new
#
# arr[1][2][3] = "foo"
# => "foo"
#
# arr[1][2][3]
# => "foo"
class Marray < Array
def [](i)
super.nil? ? self[i] = Marray.new : super
end
end
Perhaps you can simulate your multidimensional Array with a Hash. The Hash-key can by any Ruby object, so you could also take an array.
Example:
marray = {}
p marray[[1,2]] #-> nil
marray[[1,2]] = :a
p marray[[1,2]] #-> :a
Based on this idea you could define a new class.
Just a quick scenario:
=begin rdoc
Define a multidimensional array.
The keys must be Fixnum.
The following features from Array are not supported:
* negative keys (Like Array[-1])
* No methods <<, each, ...
=end
class MArray
INFINITY = Float::INFINITY
=begin rdoc
=end
def initialize(dimensions=2, *limits)
#dimensions = dimensions
raise ArgumentError if limits.size > dimensions
#limits = []
0.upto(#dimensions-1){|i|
#limits << (limits[i] || INFINITY)
}
#content = {}
end
attr_reader :dimensions
attr_reader :limits
=begin rdoc
=end
def checkkeys(keys)
raise ArgumentError, "Additional key values for %i-dimensional Array" % #dimensions if keys.size > #dimensions
raise ArgumentError, "Missing key values for %i-dimensional Array" % #dimensions if keys.size != #dimensions
raise ArgumentError, "No keys given" if keys.size == 0
keys.each_with_index{|key,i|
raise ArgumentError, "Exceeded limit for %i dimension" % (i+1) if key > #limits[i]
raise ArgumentError, "Only positive numbers allowed" if key < 1
}
end
def[]=(*keys)
data = keys.pop
checkkeys(keys)
#content[keys] = data
end
def[](*keys)
checkkeys(keys)
#content[keys]
end
end
This can be used as:
arr = MArray.new()
arr[1,1] = 3
arr[2,2] = 3
If you need a predefined matrix 2x2 you can use it as:
arr = MArray.new(2,2,2)
arr[1,1] = 3
arr[2,2] = 3
#~ arr[3,2] = 3 #Exceeded limit for 1 dimension (ArgumentError)
I could imagine how to handle commands like << or each in a two-dimensional array, but not in multidimensional ones.
It might help to remember that the array is an object in ruby, and objects are not (by default) created simply by naming them or naming a the object reference. Here is a routine for creating a 3 dimension array and dumping it to the screen for verification:
def Create3DimensionArray(x, y, z, default)
n = 0 # verification code only
ar = Array.new(x)
for i in 0...x
ar[i] = Array.new(y)
for j in 0...y
ar[i][j] = Array.new(z, default)
for k in 0...z # verification code only
ar[i][j][k] = n # verification code only
n += 1 # verification code only
end # verification code only
end
end
return ar
end
# Create sample and verify
ar = Create3DimensionArray(3, 7, 10, 0)
for x in ar
puts "||"
for y in x
puts "|"
for z in y
printf "%d ", z
end
end
end
Here is an implementation of a 3D array class in ruby, in this case the default value is 0
class Array3
def initialize
#store = [[[]]]
end
def [](a,b,c)
if #store[a]==nil ||
#store[a][b]==nil ||
#store[a][b][c]==nil
return 0
else
return #store[a][b][c]
end
end
def []=(a,b,c,x)
#store[a] = [[]] if #store[a]==nil
#store[a][b] = [] if #store[a][b]==nil
#store[a][b][c] = x
end
end
array = Array3.new
array[1,2,3] = 4
puts array[1,2,3] # => 4
puts array[1,1,1] # => 0