Combine all combinations to get complete sets - ruby

I have an array:
arr = [1, 2, 3]
I want to find all combinations and then combine the combinations to get arrays that contain all the elements of arr only once. The sequence doesn't matter. The first combination should return something like
combis = [
[1], [2], [3],
[1, 2], [1, 3], [2, 3],
[1, 2, 3]
]
I need valid that has the combinations of combis that contain each value from arr exactly once. So:
valid = [
[[1], [2], [3]],
[[1], [2, 3]],
[[2], [1, 3]],
[[3], [1, 2]],
[[1, 2, 3]]
]
This gets large very quickly, so I need a way to do this without using the combination function twice and then filtering out the incorrect ones.
I feel I need to use some kind of tree structure and recursion to generate the second set of combinations and stop traversing when it is no longer a valid final set.
Would be great if someone could help me with the (pseudo)code for this.

Use Enumerator::Lazy to reject unwanted / invalid combinations immediately:
combis = 1.upto(arr.size).each_with_object([]) do |i, acc|
acc.concat arr.combination(i).to_a
end
#⇒ [[1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]
valid = 1.upto(arr.size).each_with_object([]) do |i, acc|
acc.concat(
# ⇓⇓⇓⇓ THIS
combis.combination(i).lazy.select do |e|
items = e.flatten
items.uniq.size == items.size && items | arr == items
end.to_a
)
end
#⇒ [[[1, 2, 3]], [[1], [2, 3]], [[2], [1, 3]], [[3], [1, 2]], [[1], [2], [3]]]

Related

ruby set isn't unique

For some reason the following code produce a set with duplicate values.
I'm not sure how uniqueness of an array in ruby is defined so maybe this is somehow expectable?
require 'set'
xs = [1, 2, 3]
xss = Set.new []
xs.each do |x|
xss.merge xss.to_a.map{|xs| xs.push x}
xss.add [x]
p xss
end
will prints
#<Set: {[1]}>
#<Set: {[1, 2], [1, 2], [2]}>
#<Set: {[1, 2, 3, 3], [1, 2, 3, 3], [2, 3], [1, 2, 3, 3], [2, 3], [3]}>
What's wrong?
EDIT
change xs.push x to xs + [x] will fix it.
You are effectively altering the objects within the set, which is not allowed.
From the documentation:
Set assumes that the identity of each element does not change while it is stored. Modifying an element of a set will render the set to an unreliable state.
Regarding your comment
I want #<Set: {[1], [1, 2], [2], [1, 3], [1, 2, 3], [2, 3], [3]}>
You could use Array#combination:
a = [1, 2, 3]
(1..a.size).flat_map { |n| a.combination(n).to_a }
#=> [[1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]

Inserting elements into new array and then deleting from old array, some elements getting ignored

I'm trying to remove pairs of the smallest and largest elements from an Array and store them in a second one. Is there a better way to do this or a Ruby method I don't know about that could accomplish something like this?
Here's my code:
nums = [1, 2, 3, 4, 5, 6]
pairs = []; for n in nums
pairs << [n, nums.last]
nums.delete nums.last
nums.delete n
end
Current result:
nums
#=> [2, 4]
pairs
#=> [[1, 6], [3, 5]]
Expected result:
nums
#=> []
pairs
#=> [[1, 6], [2, 5], [3, 4]]
Assuming nums is sorted and can be modified, I like this way because it has a mechanical feel about it:
pairs = (nums.size/2).times.map { [nums.shift, nums.pop] }
#=> [[1, 6], [2, 5], [3, 4]]
nums
#=> []
I see #Drenmi has the same idea of using shift and pop.
If you don't want to modify nums, you could of course operate on a copy.
Enumerating over an Array while deleting it's content is generally not advisible. Here's an alternative solution:
nums = *(1..6)
#=> [1, 2, 3, 4, 5, 6]
pairs = []
#=> []
until nums.size < 2 do
pairs << [nums.shift, nums.pop]
end
pairs
#=> [[1, 6], [2, 5], [3, 4]]

How to make an array containing a duplicate of an array

I couldn't find a way to build an array such as
[ [1,2,3] , [1,2,3] , [1,2,3] , [1,2,3] , [1,2,3] ]
given [1,2,3] and the number 5. I guess there are some kind of operators on arrays, such as product of mult, but none in the doc does it. Please tell me. I missed something very simple.
Array.new(5, [1, 2, 3]) or Array.new(5) { [1, 2, 3] }
Array.new(size, default_object) creates an array with an initial size, filled with the default object you specify. Keep in mind that if you mutate any of the nested arrays, you'll mutate all of them, since each element is a reference to the same object.
array = Array.new(5, [1, 2, 3])
array.first << 4
array # => [[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]]
Array.new(size) { default_object } lets you create an array with separate objects.
array = Array.new(5) { [1, 2, 3] }
array.first << 4
array #=> [[1, 2, 3, 4], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]
Look up at the very top of the page you linked to, under the section entitled "Creating Arrays" for some more ways to create arrays.
Why not just use:
[[1, 2, 3]] * 5
# => [[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]
The documentation for Array.* says:
...returns a new array built by concatenating the int copies of self.
Typically we'd want to create a repeating single-level array:
[1, 2, 3] * 2
# => [1, 2, 3, 1, 2, 3]
but there's nothing to say we can't use a sub-array like I did above.
It looks like mutating one of the subarrays mutates all of them, but that may be what someone wants.
It's like Array.new(5, [1,2,3]):
foo = [[1, 2, 3]] * 2
foo[0][0] = 4
foo # => [[4, 2, 3], [4, 2, 3]]
foo = Array.new(2, [1,2,3])
foo[0][0] = 4
foo # => [[4, 2, 3], [4, 2, 3]]
A work-around, if that's not the behavior wanted is:
foo = ([[1, 2, 3]] * 2).map { |a| [*a] }
foo[0][0] = 4
foo # => [[4, 2, 3], [1, 2, 3]]
But, at that point it's not as convenient, so I'd use the default Array.new(n) {…} behavior.

Creating pairs from an Array?

Is there a simple way to create pairs from an array?
For example, if I have an array [1,2,3,4] how would I go about trying to return this array?
[[1,2], [1,3], [1,4], [2,1], [2,3], [2,4], [3,1], [3,2], [3,4], [4,1], [4,2], [4,3]]
Every element is paired with every other other element except itself, and duplicates are allowed.
You can use Array#permutation for this:
[1,2,3,4].permutation(2).to_a
# => [[1, 2], [1, 3], [1, 4], [2, 1], [2, 3], [2, 4], [3, 1], [3, 2], [3, 4], [4, 1], [4, 2], [4, 3]]
[1,2,3,4].permutation(2).map{ |n| "(#{ n.join(",") })" }
# => ["(1,2)", "(1,3)", "(1,4)", "(2,1)", "(2,3)", "(2,4)", "(3,1)", "(3,2)", "(3,4)", "(4,1)", "(4,2)", "(4,3)"]

Sorting an array by two values

Suppose I have
an_array = [[2, 3], [1, 4], [1, 3], [2, 1], [1, 2]]
I want to sort this array by the first value of each inner array, and then by the second (so the sorted array should look like this: [[1, 2], [1, 3], [1, 4], [2, 1], [2, 3]])
What's the most readable way to do this?
This is the default behavior for sorting arrays (see the Array#<=> method definition for proof). You should just be able to do:
an_array.sort
If you want some non-default behaviour, investigate sort_by (ruby 1.8.7+)
e.g. sort by the second element then by the first
a.sort_by {|e| [e[1], e[0]]} # => [[2, 1], [1, 2], [1, 3], [2, 3], [1, 4]]
or sort by the first element ascending and then the second element descending
a.sort_by {|e| [e[0], -e[1]]} # => [[1, 4], [1, 3], [1, 2], [2, 3], [2, 1]]
an_array.sort

Resources