I was just messing about trying to get all the 2, 3 and 4 combos in a size 4 array (e.g 1&2,1&3,1&4,2&3 and so on) and I came across this weird issue that I cannot figure out. Why is primary_num returning 4 on the 3rd loop but the index 0 value is 3, shouldn't it return 3.
The code is partial code but obviously can't complete it until I figure this part out. My next plan was to try a recursive function but was curious why this is happening when it works fine on loop 1 & 2. I know there is a permutations method but I am just experimenting.
lucky15 = [1,2,3,4]
doubles = []
triples = []
fourfold = []
lucky15.each_with_index do |primary_num, index|
lucky15.delete(index)
p lucky15[0]
p primary_num
p lucky15
end
The output for the puts was:
1 #p lucky15[0]
1 #p primary_num
[1, 2, 3, 4]
2 #p lucky15[0]
2 #p primary_num
[2, 3, 4]
3 #p lucky15[0]
4 #p primary_num <--- why 4 not 3????
[3, 4]
To explain what I was trying to do as my first revision:
lucky15 = [1,2,3,4]
doubles = []
triples = []
fourfold = []
lucky15.each_with_index do |primary_num, index|
lucky15.delete(index)
each.lucky15 do |num|
doubles << "#{primary_num} && #{num}"
end
end
puts doubles
CodePudding user response:
Looks like the delete
method wasn't doing what you thought it was (same here, I had to run a modified version of this with more printing to see it):
lucky15 = [1,2,3,4]
doubles = []
triples = []
fourfold = []
lucky15.each_with_index do |primary_num, index|
puts "Index: #{index}"
puts "0th element before delete: #{lucky15[0]}"
lucky15.delete(index)
puts "0th element after delete: #{lucky15[0]}"
puts "primary_num: #{primary_num}"
puts "lucky15: #{lucky15}"
end
Output:
Index: 0
0th element before delete: 1
0th element after delete: 1
primary_num: 1
lucky15: [1, 2, 3, 4]
Index: 1
0th element before delete: 1
0th element after delete: 2
primary_num: 2
lucky15: [2, 3, 4]
Index: 2
0th element before delete: 2
0th element after delete: 3
primary_num: 4
lucky15: [3, 4]
The index
variable is holding the index each time, but delete
is searching for the element in the array and deleting it if it's present. So when you use delete
that way, you're deleting an element equal to the index from the array during each iteration, if such an element exists in the array during that iteration.
You probably want delete_at
(https://ruby-doc.org/core-3.0.0/Array.html#method-i-delete_at).
CodePudding user response:
trying to get all the 2, 3 and 4 combos
To calculate combinations manually, you typically use nested loops. For "doubles", you could use:
lucky15 = [1, 2, 3, 4]
doubles = []
(0...lucky15.size-1).each do |i|
(i 1...lucky15.size).each do |j|
doubles << lucky15.values_at(i, j)
end
end
doubles #=> [[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]
The outer loop increments an index i
from 0
to 2
(because 2
is the maximum starting-index for a "2 combo"). The inner loop then increments another index j
from i
's successor up to 3
(the array's end index). This way, the inner loop "skips" the indices that have already been visited by i
: (so there's no need to delete anything)
1 2 3 4 # array values
0 1 2 3 # array indices
i j # lucky15.values_at(0, 1)
1 2 3 4
0 1 2 3
i j # lucky15.values_at(0, 2)
1 2 3 4
0 1 2 3
i j # lucky15.values_at(0, 3)
1 2 3 4
0 1 2 3
i j # lucky15.values_at(1, 2)
1 2 3 4
0 1 2 3
i j # lucky15.values_at(1, 3)
1 2 3 4
0 1 2 3
i j # lucky15.values_at(2, 3)
To get "triples", you need another level:
triples = []
(0...lucky15.size-2).each do |i|
(i 1...lucky15.size-1).each do |j|
(j 1...lucky15.size).each do |k|
triples << lucky15.values_at(i, j, k)
end
end
end
triples #=> [[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]]
Visualized:
1 2 3 4
0 1 2 3
i j k
1 2 3 4
0 1 2 3
i j k
1 2 3 4
0 1 2 3
i j k
1 2 3 4
0 1 2 3
i j k
However, Ruby already has the above methods built-in as combination
so there's no need to re-invent the wheel:
doubles = lucky15.combination(2).to_a
#=> [[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]
triples = lucky15.combination(3).to_a
#=> [[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]]