Could someone tell me how I can achieve replacing an element in this 2D array? I tried each, include and replace and wasn't able to figure out where I am going wrong. Thank you in advance for any help.
class Lotto
def initialize
#lotto_slip = Array.new(5) {Array(6.times.map{rand(1..60)})}
end
def current_pick
#number = rand(1..60).to_s
puts "The number is #{#number}."
end
def has_number
#prints out initial slip
#lotto_slip.each {|x| p x}
#Prints slip with an "X" replacing number if is on slip
#Ex: #number equals 4th number on slip --> 1, 2, 3, X, 5, 6
#lotto_slip.each do |z|
if z.include?(#number)
z = "X"
p #lotto_slip
else
z = z
p #lotto_slip
end
end
end
end
test = Lotto.new
test.current_pick
test.has_number
Let me know if this works out (tried to reduce the variations from 1 to 10 in order to be able to test easier):
class Lotto
def initialize
#lotto_slip = Array.new(5) {Array(6.times.map{rand(1..10)})}
end
def current_pick
#number = rand(1..10)
puts "The number is #{#number}."
end
def has_number
#prints out initial slip
#lotto_slip.each {|x| p x}
#Prints slip with an "X" replacing number if is on slip
#Ex: #number equals 4th number on slip --> 1, 2, 3, X, 5, 6
#lotto_slip.each do |z|
if z.include?(#number)
p "#{#number} included in #{z}"
z.map! { |x| x == #number ? 'X' : x}
end
end
#lotto_slip
end
end
test = Lotto.new
test.current_pick
p test.has_number
The problems I saw with your code are:
You don't need the to_s for this line #number = rand(1..60).to_s, else how are you going to compare the numbers produced by the array with an actual string?
You need to re-generate the array instead of re-assigning, that's why I've replaced all of that code with z.map! { |x| x == #number ? 'X' : x} which basically re-generates the entire array.
Not necessary iterate with each, use map:
#lotto_slip = Array.new(5) {Array(6.times.map{rand(1..60)})}
#=> [[25, 22, 10, 10, 57, 17], [37, 4, 8, 52, 55, 7], [44, 30, 58, 58, 50, 19], [49, 49, 24, 31, 26, 28], [24, 18, 39, 27, 8, 54]]
#number = 24
#lotto_slip.map{|x| x.map{|x| x == #number ? 'X' : x}}
#=> [[25, 22, 10, 10, 57, 17], [37, 4, 8, 52, 55, 7], [44, 30, 58, 58, 50, 19], [49, 49, "X", 31, 26, 28], ["X", 18, 39, 27, 8, 54]]
I have an array of numbers as below:
[11, 12, 13, 14, 19, 20, 21, 29, 30, 33]
I would like to reduce this array to:
[[11,14], [19,21], [29,30], [33,33]]
Identify consequent numbers in an array and push only the start and end of its ranges.
How to achieve this?
Exactly some problem is solved to give an example for slice_before method in ruby docs:
a = [0, 2, 3, 4, 6, 7, 9]
prev = a[0]
p a.slice_before { |e|
prev, prev2 = e, prev
prev2 + 1 != e
}.map { |es|
es.length <= 2 ? es.join(",") : "#{es.first}-#{es.last}"
}.join(",")
In your case you need to tweak it a little:
a = [11, 12, 13, 14, 19, 20, 21, 29, 30, 33]
prev = a[0]
p a.slice_before { |e|
prev, prev2 = e, prev
prev2 + 1 != e
}.map { |es|
[es.first, es.last]
}
Here's another way, using an enumerator with Enumerator#next and Enumerator#peek. It works for any collection that implements succ (aka next).
Code
def group_consecs(a)
enum = a.each
pairs = [[enum.next]]
loop do
if pairs.last.last.succ == enum.peek
pairs.last << enum.next
else
pairs << [enum.next]
end
end
pairs.map { |g| (g.size > 1) ? g : g*2 }
end
Note that Enumerator#peek raises a StopInteration exception if the enumerator enum is already at the end when enum.peek is invoked. That exception is handled by Kernel#loop, which breaks the loop.
Examples
a = [11, 12, 13, 14, 19, 20, 21, 29, 30, 33]
group_consecs(a)
#=> [[11, 12, 13, 14], [19, 20, 21], [29, 30], [33, 33]]
a = ['a','b','c','f','g','i','l','m']
group_consecs(a)
#=> [["a", "b", "c"], ["f", "g"], ["i", "i"], ["l", "m"]]
a = ['aa','ab','ac','af','ag','ai','al','am']
group_consecs(a)
#=> [["aa", "ab", "ac"], ["af", "ag"], ["ai, ai"], ["al", "am"]]
a = [:a,:b,:c,:f,:g,:i,:l,:m]
group_consecs(a)
#=> [[:a, :b, :c], [:f, :g], [:i, :i], [:l, :m]]
Generate an array of seven date objects for an example, then group consecutive dates:
require 'date'
today = Date.today
a = 10.times.map { today = today.succ }.values_at(0,1,2,5,6,8,9)
#=> [#<Date: 2014-08-07 ((2456877j,0s,0n),+0s,2299161j)>,
# #<Date: 2014-08-08 ((2456878j,0s,0n),+0s,2299161j)>,
# #<Date: 2014-08-09 ((2456879j,0s,0n),+0s,2299161j)>,
# #<Date: 2014-08-12 ((2456882j,0s,0n),+0s,2299161j)>,
# #<Date: 2014-08-13 ((2456883j,0s,0n),+0s,2299161j)>,
# #<Date: 2014-08-15 ((2456885j,0s,0n),+0s,2299161j)>,
# #<Date: 2014-08-16 ((2456886j,0s,0n),+0s,2299161j)>]
group_consecs(a)
#=> [[#<Date: 2014-08-07 ((2456877j,0s,0n),+0s,2299161j)>,
# #<Date: 2014-08-08 ((2456878j,0s,0n),+0s,2299161j)>,
# #<Date: 2014-08-09 ((2456879j,0s,0n),+0s,2299161j)>
# ],
# [#<Date: 2014-08-12 ((2456882j,0s,0n),+0s,2299161j)>,
# #<Date: 2014-08-13 ((2456883j,0s,0n),+0s,2299161j)>
# ],
# [#<Date: 2014-08-15 ((2456885j,0s,0n),+0s,2299161j)>,
# #<Date: 2014-08-16 ((2456886j,0s,0n),+0s,2299161j)>
# ]]
This is some code I wrote for a project a while ago:
class Array
# [1,2,4,5,6,7,9,13].to_ranges # => [1..2, 4..7, 9..9, 13..13]
# [1,2,4,5,6,7,9,13].to_ranges(true) # => [1..2, 4..7, 9, 13]
def to_ranges(non_ranges_ok=false)
self.sort.each_with_index.chunk { |x, i| x - i }.map { |diff, pairs|
if (non_ranges_ok)
pairs.first[0] == pairs.last[0] ? pairs.first[0] : pairs.first[0] .. pairs.last[0]
else
pairs.first[0] .. pairs.last[0]
end
}
end
end
if ($0 == __FILE__)
require 'awesome_print'
ary = [1, 2, 4, 5, 6, 7, 9, 13, 12]
ary.to_ranges(false) # => [1..2, 4..7, 9..9, 12..13]
ary.to_ranges(true) # => [1..2, 4..7, 9, 12..13]
ary = [1, 2, 4, 8, 5, 6, 7, 3, 9, 11, 12, 10]
ary.to_ranges(false) # => [1..12]
ary.to_ranges(true) # => [1..12]
end
It's easy to change that to only return the start/end pairs:
class Array
def to_range_pairs(non_ranges_ok=false)
self.sort.each_with_index.chunk { |x, i| x - i }.map { |diff, pairs|
if (non_ranges_ok)
pairs.first[0] == pairs.last[0] ? [pairs.first[0]] : [pairs.first[0], pairs.last[0]]
else
[pairs.first[0], pairs.last[0]]
end
}
end
end
if ($0 == __FILE__)
require 'awesome_print'
ary = [1, 2, 4, 5, 6, 7, 9, 13, 12]
ary.to_range_pairs(false) # => [[1, 2], [4, 7], [9, 9], [12, 13]]
ary.to_range_pairs(true) # => [[1, 2], [4, 7], [9], [12, 13]]
ary = [1, 2, 4, 8, 5, 6, 7, 3, 9, 11, 12, 10]
ary.to_range_pairs(false) # => [[1, 12]]
ary.to_range_pairs(true) # => [[1, 12]]
end
Here's an elegant solution:
arr = [11, 12, 13, 14, 19, 20, 21, 29, 30, 33]
output = []
# Sort array
arr.sort!
# Loop through each element in the list
arr.each do |element|
# Set defaults - for if there are no consecutive numbers in the list
start = element
endd = element
# Loop through consecutive numbers and check if they are inside the list
i = 1
while arr.include?(element+i) do
# Set element as endd
endd = element+i
# Remove element from list
arr.delete(element+i)
# Increment i
i += 1
end
# Push [start, endd] pair to output
output.push([start, endd])
end
[Edit: Ha! I misunderstood the question. In your example, for the array
a = [11, 12, 13, 14, 19, 20, 21, 29, 30, 33]
you showed the desired array of pairs to be:
[[11,14], [19,21], [29,30], [33,33]]
which correspond to the following offsets in a:
[[0,3], [4,6], [7,8], [9,9]]
These pairs respective span the first 4 elements, the next 3 elements, then next 2 elements and the next element (by coincidence, evidently). I thought you wanted such pairs, each with a span one less than the previous, and the span of the first being as large as possible. If you have a quick look at my examples below, my assumption may be clearer. Looking back I don't know why I didn't understand the question correctly (I should have looked at the answers), but there you have it.
Despite my mistake, I'll leave this up as I found it an interesting problem, and had the opportunity to use the quadratic formula in the solution.
tidE]
This is how I would do it.
Code
def pull_pairs(a)
n = ((-1 + Math.sqrt(1.0 + 8*a.size))/2).to_i
cum = 0
n.downto(1).map do |i|
first = cum
cum += i
[a[first], a[cum-1]]
end
end
Examples
a = %w{a b c d e f g h i j k l}
#=> ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"]
pull_pairs(a)
#=> [["a", "d"], ["e", "g"], ["h", "i"], ["j", "j"]]
a = [*(1..25)]
#=> [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
# 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]
pull_pairs(a)
#=> [[1, 6], [7, 11], [12, 15], [16, 18], [19, 20], [21, 21]]
a = [*(1..990)]
#=> [1, 2,..., 990]
pull_pairs(a)
#=> [[1, 44], [45, 87],..., [988, 989], [990, 990]]
Explanation
First, we'll compute the the number of pairs of values in the array we will produce. We are given an array (expressed algebraically):
a = [a0,a1,...a(m-1)]
where m = a.size.
Given n > 0, the array to be produced is:
[[a0,a(n-1)], [a(n),a(2n-2)],...,[a(t),a(t)]]
These elements span the first n+(n-1)+...+1 elements of a. As this is an arithmetic progession, the sum equals n(n+1)/2. Ergo,
t = n(n+1)/2 - 1
Now t <= m-1, so we maximize the number of pairs in the output array by choosing the largest n such that
n(n+1)/2 <= m
which is the float solution for n in the quadratic:
n^2+n-2m = 0
rounded down to an integer, which is
int((-1+sqrt(1^1+4(1)(2m))/2)
or
int((-1+sqrt(1+8m))/2)
Suppose
a = %w{a b c d e f g h i j k l}
Then m (=a.size) = 12, so:
n = int((-1+sqrt(97))/2) = 4
and the desired array would be:
[['a','d'],['e','g'],['h','i'],['j','j']]
Once n has been computed, constructing the array of pairs is straightforward.
I have an array in Ruby like [3,4,5] and I want to create sub-arrays by diving or multiplying. For example, I want to multiply each number in the array by 2, 3, and 4, returning [[6,9,12],[8,12,16],[10,15,20]]
After that, what's the best way to count the total number of units? In this example, it would be 9, while array.count would return 3.
Thanks
The simplest way I could think of was:
[3,4,5].map { |v|
[3,4,5].map { |w|
w * v
}
}
I'm sure there is a more elegant way.
As for the count you can use flatten to turn it into a single array containing all the elements.
[[9, 12, 15], [12, 16, 20], [15, 20, 25]].flatten
=> [9, 12, 15, 12, 16, 20, 15, 20, 25]
You might find it convenient to use matrix operations for this, particularly if it is one step among several involving matrices, vectors, and/or scalars.
Code
require 'matrix'
def doit(arr1, arr2)
(Matrix.column_vector(arr2) * Matrix.row_vector(arr1)).to_a
end
def nbr_elements(arr1, arr2) arr1.size * arr2.size end
Examples
arr1 = [3,4,5]
arr2 = [3,4,5]
doit(arr1, arr2)
#=> [[ 9, 12, 15],
# [12, 16, 20],
# [15, 20, 25]]
nbr_elements(arr1, arr2)
#=> 9
doit([1,2,3], [4,5,6,7])
#=> [[4, 8, 12],
# [5, 10, 15],
# [6, 12, 18],
# [7, 14, 21]]
nbr_elements([1,2,3], [4,5,6,7])
#=> 12
Alternative
If you don't want to use matrix operations, you could do it like this:
arr2.map { |e| [e].product(arr1).map { |e,f| e*f } }
Here's an example:
arr1 = [1,2,3]
arr2 = [4,5,6,7]
arr2.map { |e| [e].product(arr1).map { |e,f| e*f } }
#=> [[4, 8, 12],
# [5, 10, 15],
# [6, 12, 18],
# [7, 14, 21]]
I need a ruby formula to create an array of integers. The array must be every other 2 numbers as follows.
[2, 3, 6, 7, 10, 11, 14, 15, 18, 19...]
I have read a lot about how I can do every other number or multiples, but I am not sure of the best way to achieve what I need.
Here's an approach that works on any array.
def every_other_two arr
arr.select.with_index do |_, idx|
idx % 4 > 1
end
end
every_other_two((0...20).to_a) # => [2, 3, 6, 7, 10, 11, 14, 15, 18, 19]
# it works on any array
every_other_two %w{one two three four five six} # => ["three", "four"]
array = []
#Change 100000 to whatever is your upper limit
100000.times do |i|
array << i if i%4 > 1
end
This code works for any start number to any end limit
i = 3
j = 19
x =[]
(i...j).each do |y|
x << y if (y-i)%4<2
end
puts x
this should work
For fun, using lazy enumerables (requires Ruby 2.0 or gem enumerable-lazy):
(2..Float::INFINITY).step(4).lazy.map(&:to_i).flat_map { |x| [x, x+1] }.first(8)
#=> => [2, 3, 6, 7, 10, 11, 14, 15]
here's a solution that works with infinite streams:
enum = Enumerator.new do |y|
(2...1/0.0).each_slice(4) do |slice|
slice[0 .. 1].each { |n| y.yield(n) }
end
end
enum.first(10) #=> [2, 3, 6, 7, 10, 11, 14, 15, 18, 19]
enum.each do |n|
puts n
end
Single Liner:
(0..20).to_a.reduce([0,[]]){|(count,arr),ele| arr << ele if count%4 > 1;
[count+1,arr] }.last
Explanation:
Starts the reduce look with 0,[] in count,arr vars
Add current element to array if condition satisfied. Block returns increment and arr for the next iteration.
I agree though that it is not so much of a single liner though and a bit complex looking.
Here's a slightly more general version of Sergio's fine answer
module Enumerable
def every_other(slice=1)
mod = slice*2
res = select.with_index { |_, i| i % mod >= slice }
block_given? ? res.map{|x| yield(x)} : res
end
end
irb> (0...20).every_other
=> [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
irb> (0...20).every_other(2)
=> [2, 3, 6, 7, 10, 11, 14, 15, 18, 19]
irb> (0...20).every_other(3)
=> [3, 4, 5, 9, 10, 11, 15, 16, 17]
irb> (0...20).every_other(5) {|v| v*10 }
=> [50, 60, 70, 80, 90, 150, 160, 170, 180, 190]