Find efficient maximum of groupings in all sets - ruby

I have a 2D array and want to generate a 3D array that will show the most efficient groupings for all sets. Example:
[[1, 2],
[1, 2, 3, 4],
[3, 4],
[1, 2, 5]]
Result:
[[[1, 2]],
[[1, 2], [3, 4]],
[[3, 4]],
[[1, 2], [5]]]
I think I would need to do a nested loop and determine the intersection and differences to generate the 3D array. However, inject(&:&) seems like it might solve it more elegantly, though I'm a bit new to inject and unsure how to implement it for this problem. This is to be done in Ruby.
Any help is appreciated. Thanks!
--Update--
By efficient groupings I mean find the best combination that generates the least amount of total sets in the result by finding the largest duplicate sets.
Another example:
[[1, 2, 3, 4],
[1, 4],
[1, 3, 4],
[1, 2, 3, 4, 5],
[2, 5]]
Possible Result (8 total sets):
[[[1, 3, 4], [2]],
[[1, 4]],
[[1, 4], [3]],
[[1, 3, 4], [2, 5]],
[[2, 5]]]
This is a good result, but the first set could be optimized.
Better Result (7 total sets):
[[[1, 2, 3, 4]],
[[1, 4]],
[[1, 4], [3]],
[[1, 2, 3, 4], [5]],
[[2, 5]]]
Both results contain a total of 5 unique sets. The sets in the better result are (1, 2, 3, 4), (1, 4), (3), (5), and (2, 5). The total number of sets in the better result is 7 as opposed to 8 in the possible result. We want the least amount of sets.

You definitely should explain what "the most efficient grouping" means. In the meantime, if you just need to split arrays into 2-element chunks, just combine map and each_slice:
arr.map{|a| a.each_slice(2).to_a}
# => [[[1, 2]], [[1, 2], [3, 4]], [[3, 4]], [[1, 2], [5]]]

First you should figure out the algorithm in pseudocode for what you want to do (its not the Ruby that's keeping you back right now). Then go use these ruby primatives to make it happen
http://ruby-doc.org/core/classes/Enumerable.html
http://www.ruby-doc.org/core/classes/Array.html
http://corelib.rubyonrails.org/classes/Set.html

Related

Are there any algorithm that solves the following problem in time less than O(n!)?

Are there any algorithm that solves the following problem in time less than O(n!), like polynomial time?
Otherwise, for this problem, does not anyone have found any polynomial time algorithm, like NP problems?
Input: n (number of elements)
Output: a list of all combinations of two, where, from top of the list, each unit of combinations of n/2 must have all elements.
Example 1
Input: n=4
Output:
[0, 1], [2, 3],
[0, 2], [1, 3],
[0, 3], [1, 2]
Example 2
Input: n=8
Output:
[0, 1], [2, 3], [4, 5], [6, 7],
[0, 2], [1, 3], [4, 6], [5, 7],
[0, 3], [1, 2], [4, 7], [5, 6],
[0, 4], [1, 5], [2, 6], [3, 7],
[0, 5], [1, 4], [2, 7], [3, 6],
[0, 6], [1, 7], [2, 4], [3, 5],
[0, 7], [1, 6], [2, 5], [3, 4]
P.S.
The following answer does not meet the requirements.
The first two (= n/2) pairs ([0, 1], [0, 2]) do not have "3", so the answer does not meet the condition where "0" and "1", "2", "3" must be in the first two pairs.
>>> n=4
>>> for i in range(0, n-1):
... for j in range(i+1,n):
... print( [i, j] )
...
[0, 1]
[0, 2]
[0, 3]
[1, 2]
[1, 3]
[2, 3]
As I said in my comment, this appears to be a type of (relaxed) Sports League Scheduling problem. If I understand what you are asking for, it can be summarized as follows:
Given a positive even integer N generate a set of n/2 "rounds" of pairings with the following qualities:
A pairing is a pair of two different integers [a, b] such that a and b are integers from 0..n-1 and a < b.
A round consists of n/2 pairings, such that every element from 0..n-1 appears exactly once in a pairing in the round, and
All pairings are unique across all rounds (that is no pairing ever appears more than once in the complete solution).
Assuming that this is a correct formulation of your problem, then the answer is
Yes, this can be done in O(n^2).
Further, not only can it be done, there exists a simple method to solve it for any even N:
For the first round, make n-1 pairs, filling in the first element of the pairs with the integers from 0 to (n/2)-1 going left-to-right. This how it would look for N=8:
[0, ], [1, ], [2, ], [3, ]
Then, fill in the second elements with (n/2) to n-1, but going right-to-left:
[0, 7], [1, 6], [2, 5], [3, 4]
This completes your first round.
For the next round, copy the first round, but keeping 0 in the same place, move the remaining left-side elements up the list, and the right-side elements down the list. When an element reaches the end of the list, reverse direction and swap them from first elements to second elements (or vice-versa):
----------------------->
[0, 7], [1, 6], [2, 5], [3, 4]
<-----------------------
Becomes
----------------------->
[0, 6], [7, 5], [1, 4], [2, 3]
<-----------------------
Now you just continue this process until you have N/2 rounds:
[0, 7], [1, 6], [2, 5], [3, 4]
[0, 6], [7, 5], [1, 4], [2, 3]
[0, 5], [6, 4], [7, 3], [1, 2]
[0, 4], [5, 3], [6, 2], [7, 1]
Finally swap any pairings where the first element happens to be greater than the second:
[0, 7], [1, 6], [2, 5], [3, 4]
[0, 6], [5, 7], [1, 4], [2, 3]
[0, 5], [4, 6], [3, 7], [1, 2]
[0, 4], [3, 5], [2, 6], [1, 7]
If you check this solution you will find that it fulfills all of the constraints. This solutions works for any even value of N and obviously runs in O(n^2) time.
Yes, this problem can be solved in quadratic time. It is not too hard to explicitly construct these pairings.
It is quite helpful to consider a regular (n-1)-gon with one additional point in the middle. Then take the lines through one of the (n-1) endpoints and the midpoint and choose the pairs given by the symmetry of this line.

Why does this recursive Prolog predicate add some "_1508"-like numbers to lists?

My task is to split a given sorted list (LSorted) into several other ones, where the first one would contain values from the LSorted that are smaller than the first prime number (1 is not considered prime) (from Primes list), the second one would contain values from LSorted smaller than the second prime number but greater or equal to the first prime, etc.
ans(L, Res):-
max_list(L, X), /*determine the max value X of L*/
listPrimes(X, Primes), /*generate a list of primes up to X and the prime greater than X*/
msort(L, LSorted), /*sort L*/
ans_recur(LSorted, Primes, Res),!.
ans_recur([], _, [[]|[]]).
ans_recur([InH|Input], [PrimeH|Primes], [[InH|Res]|ResT]):-
InH < PrimeH,
ans_recur(Input, [PrimeH|Primes], [Res|ResT]).
ans_recur([InH|Input], [_|Primes], [_|ResT]):-
ans_recur([InH|Input], Primes, ResT).
When I run a query: ans([1,2,3,4], L)., I get this result:
L = [_1508, [1|_1522], [2|_1534], [3, 4]], while I expect [[1], [2], [3,4]]. The program does "put" the numbers into the "correct" lists, but adds some values like _1508.
As far as I understand, the reason for that is that Prolog is trying to assign some value to Res in ans_recur predicate, but why does it do that?
Tracing:
Call:ans([1, 1, 2, 2, 3, 4], _13636)
Call:lists:max_list([1, 1, 2, 2, 3, 4], _14050)
Exit:lists:max_list([1, 1, 2, 2, 3, 4], 4)
Call:listPrimes(4, _14080)
Exit:listPrimes(4, [1, 2, 3, 5])
Call:sort([1, 1, 2, 2, 3, 4], _14224)
Exit:sort([1, 1, 2, 2, 3, 4], [1, 2, 3, 4])
Call:ans_recur([1, 2, 3, 4], [1, 2, 3, 5], _13636)
Call:1<1
Fail:1<1
Redo:ans_recur([1, 2, 3, 4], [1, 2, 3, 5], _13636)
Call:ans_recur([1, 2, 3, 4], [2, 3, 5], _14156)
Call:1<2
Exit:1<2
Call:ans_recur([2, 3, 4], [2, 3, 5], [_14174|_14168])
Call:2<2
Fail:2<2
Redo:ans_recur([2, 3, 4], [2, 3, 5], [_14174|_14168])
Call:ans_recur([2, 3, 4], [3, 5], _14168)
Call:2<3
Exit:2<3
Call:ans_recur([3, 4], [3, 5], [_14204|_14198])
Call:3<3
Fail:3<3
Redo:ans_recur([3, 4], [3, 5], [_14204|_14198])
Call:ans_recur([3, 4], [5], _14198)
Call:3<5
Exit:3<5
Call:ans_recur([4], [5], [_14234|_14228])
Call:4<5
Exit:4<5
Call:ans_recur([], [5], [_14252|_14228])
Exit:ans_recur([], [5], [[]])
Exit:ans_recur([4], [5], [[4]])
Exit:ans_recur([3, 4], [5], [[3, 4]])
Exit:ans_recur([3, 4], [3, 5], [_14204, [3, 4]])
Exit:ans_recur([2, 3, 4], [3, 5], [[2|_14204], [3, 4]])
Exit:ans_recur([2, 3, 4], [2, 3, 5], [_14174, [2|_14204], [3, 4]])
Exit:ans_recur([1, 2, 3, 4], [2, 3, 5], [[1|_14174], [2|_14204], [3, 4]])
Exit:ans_recur([1, 2, 3, 4], [1, 2, 3, 5], [_14154, [1|_14174], [2|_14204], [3, 4]])
Exit:ans([1, 1, 2, 2, 3, 4], [_14154, [1|_14174], [2|_14204], [3, 4]])
L = [_1282, [1|_1296], [2|_1308], [3, 4]]
Thanks in advance.
ans_recur([InH|Input], [PrimeH|Primes], [[InH|Res]|ResT]):-
InH < PrimeH,
ans_recur(Input, [PrimeH|Primes], [Res|ResT]).
ans_recur([InH|Input], [_|Primes], [_|ResT]):-
ans_recur([InH|Input], Primes, ResT).
What you are trying to express in these clauses is something like this:
if InH is less than the next prime, it should be part of the current running result
otherwise, it should be part of some later running result
But in the last case, the "current running result" is finished, it has no more elements. So its tail, which is so far open, must be closed. You need to change the head of the last clause accordingly:
ans_recur([InH|Input], [_|Primes], [[]|ResT]):-
This now behaves like this:
?- ans_recur([1,2,3,4,5,6,7,8,9,10], [2,3,5,7,11], Result).
Result = [[1], [2], [3, 4], [5, 6], [7, 8, 9, 10]] ;
Result = [[1], [2], [3, 4], [5], [6, 7, 8, 9|...]] ;
Result = [[1], [2], [3, 4], [], [5, 6, 7, 8|...]] ;
Result = [[1], [2], [3], [4, 5, 6], [7, 8, 9, 10]] . % further incorrect answers
The problem is that you don't express the "otherwise" condition explicitly, and Prolog will not guess implicitly that it was what you meant. You can change the last clause to this:
ans_recur([InH|Input], [PrimeH|Primes], [[]|ResT]):-
InH >= PrimeH,
ans_recur([InH|Input], Primes, ResT).
And only get the expected answer:
?- ans_recur([1,2,3,4,5,6,7,8,9,10], [2,3,5,7,11], Result).
Result = [[1], [2], [3, 4], [5, 6], [7, 8, 9, 10]] ;
false.
As you can see, I only dealt with your implementation of ans_recur/3. There might be more bugs lingering in the rest of the code. We cannot tell because the code you posted is incomplete. In the future, please only post complete programs. Many contributors will not bother to try to complete your question for you, and you will get fewer answers.

Ruby array product with asterisk

I was studying how to list out all divisors of a number and came across this solution by Marc-Andre here. In his solution, there is one part of the code which does something like this:
array.product(*arrays_of_array) # the asterisk seems to have done sth.
I tried it in irb to try play around but I couldn't make sense of the outputs. I tried:
a=[0,1,2]
b=[3,4]
c=[[5,6],[7,8]]
I understand that array.product(other_array) is a method to list all combinations of the two arrays into one. With this knowledge, I tested out several experiments
a.product(b) => [[0, 3], [0, 4], [1, 3], [1, 4], [2, 3], [2, 4]] / 6 elements
a.product(*b) => TypeError: no implicit conversion of Fixnum into Array
a.product(c) => [[0, [5, 6]], [0, [7, 8]], [1, [5, 6]], [1, [7, 8]], [2, [5, 6]], [2, [7, 8]]] / 6 elements
a.product(*c) => [[0, 5, 7], [0, 5, 8], [0, 6, 7], [0, 6, 8], [1, 5, 7], [1, 5, 8], [1, 6, 7], [1, 6, 8], [2, 5, 7], [2, 5, 8], [2, 6, 7], [2, 6, 8]]
From observation, It seems the asterisk (*) has to be applied to a multi-dimensional array? (i.e. matrix?). Without the asterisk, the product returns 6 elements and the combinations only one level. While with the asterisk, the combination will go 1 level deeper and returns 12 elements, and combine until there is no array within the combinations. Where can I find more examples to study this behaviour of the asterisk?
Edit:
I tried to introduce one more variable
d=[[[9,0],[1,2]],[[3,4],[5,6]]]
a.product(*d) => [[0, [9, 0], [3, 4]], [0, [9, 0], [5, 6]], [0, [1, 2], [3, 4]], [0, [1, 2], [5, 6]], [1, [9, 0], [3, 4]], [1, [9, 0], [5, 6]], [1, [1, 2], [3, 4]], [1, [1, 2], [5, 6]], [2, [9, 0], [3, 4]], [2, [9, 0], [5, 6]], [2, [1, 2], [3, 4]], [2, [1, 2], [5, 6]]]
So the asterisk sign only makes it go one level deeper.
In the context of finding the list of divisors. Can anyone explain what the code exactly does?
require 'prime'
def factors_of(number)
primes, powers = number.prime_division.transpose
exponents = powers.map{|i| (0..i).to_a}
divisors = exponents.shift.product(*exponents).map do |powers|
primes.zip(powers).map{|prime, power| prime ** power}.inject(:*)
end
divisors.sort.map{|div| [div, number / div]}
end
p factors_of(4800) # => [[1, 4800], [2, 2400], ..., [4800, 1]]
*(splat) is used to expand collections.
In your example, with b = [3,4],
a.product(*b)
is equivalent to
a.product(3, 4)
which generates an error because Array#product expects an Array as argument, not two integers.

Creating permutations from a multi-dimensional array in Ruby

I have the following multi-dimensional array in Ruby:
[[1,2], [3], [4,5,6]]
I need to have the following output:
[[1,3,4], [1,3,5], [1,3,6], [2,3,4], [2,3,5], [2,3,6]]
I have tried creating a recursive function, but I'm not having much luck.
Are there any Ruby functions that would help with this? Or is the only option to do it recursively?
Thanks
Yup, Array#product does just that (Cartesian product):
a = [[1,2], [3], [4,5,6]]
head, *rest = a # head = [1,2], rest = [[3], [4,5,6]]
head.product(*rest)
#=> [[1, 3, 4], [1, 3, 5], [1, 3, 6], [2, 3, 4], [2, 3, 5], [2, 3, 6]]
Another variant:
a.inject(&:product).map(&:flatten)
#=> [[1, 3, 4], [1, 3, 5], [1, 3, 6], [2, 3, 4], [2, 3, 5], [2, 3, 6]]

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