Random distribution between evenly sized buckets without repetition - algorithm

Problem
I have N items of various types evenly distributed into their own buckets determined by type. I want to create a new list that:
randomly picks from each bucket
does not pick from the same bucket twice in a row
each bucket must have (if possible) an equal amount of representation in the final list
not using language specific libraries (not easily implemented in another language)
Example
I have 12 items of 4 distinct types which means I have 4 buckets:
Bucket A - [a, a, a]
Bucket B - [b, b, b]
Bucket C - [c, c, c]
Bucket D - [d, d, d]
What I want
A list of the above items in a random distribution without any characters repeating with a size between 1 and N.
12 Items: a, d, c, a, b, a, c, d, c, b, d, b
8 Items: c, a, d, a, b, d, c, b
4 Items: c, b, d, a
3 Items: b, c, a (Skipping D)
I was trying to do this with a while loop that generates random integers until the next bucket isn't equal to the previously used bucket, but that seems inefficient, and was hoping someone else might have a better algorithm to solve this problem.

You could generate a random list of the buckets, and then randomly pick from then in order, removing the bucket from the list when you pick from it. When the list is empty, regenerate a random list of buckets, repeating until you pick the desired number of items.
Can you repeat items from the buckets? So if you pick the 1st "a" from bucket A the first time around, can you pick it a 2nd time? That'll change the solution.

Edited in response to the constraint that no draw must be consecutive from each bucket. It's simple to throw away permutations that don't meet your criteria. Now that this will fail (as is) if two buckets have identical "labels".
A little hack with itertools and random.sample for a permutation:
import random
import itertools as itr
from math import ceil
def buckets_choice(N,labels):
    items = int(ceil(float(N)/len(labels)))
    b = list(itr.chain(*(labels for _ in xrange(items))))
    while True:
        p = random.sample(b,len(b))
        cond = map( (lambda x,y: x==y), p[1:], p[:1])
        if not sum(cond):  return p[:N]
L = ['a','b','c','d']
for _ in xrange(5):
    print buckets_choice(3,L), buckets_choice(8,L), buckets_choice(12,L)
A sample run gives (quote marks removed for clarity):
(a, b, d) (b, d, c, a, d, a, b, c) (b, c, d, c, d, a, d, b, a, c, b, a)
(b, a, d) (d, a, c, c, a, b, b, d) (c, b, a, b, a, c, b, d, d, a, d, c)
(b, d, a) (b, c, c, a, b, a, d, d) (a, d, a, d, c, b, d, c, a, b, c, b)
(d, c, b) (c, d, a, b, c, b, a, d) (c, b, a, a, b, c, d, c, b, a, d, d)
(b, d, a) (c, b, b, d, c, a, d, a) (c, b, d, a, d, b, b, d, c, a, a, c)

Related

Algorithm: generate list permutation by preference

I have a function f that takes a list of items as it's single parameter and returns true if the ordering of the items is accepted or false if the ordering of the items is not accepted.
There exists at least one or more permutations of list l which f(l) returns true.
Function f is a black box (we don't have it's source code) and the type of the elements held by list l are also unknown or generic.
p is a permutation of list l according to user preferences. The most preferred item has index 0 the least preferred item has index l.size()-1
list p will always contain all elements of list l.
The goal is to find a permutation of l let's call it p_accepted where f(p_accepted) returns true and preference p is maximized.
Here's an example
given l = [a, b, c, d, e, f]
given p = [c, a, f, b, e, d]
given f([ a, b, c, d, e, f ]) = false
given f([ c, a, f, b, e, d ]) = false
given f([ d, e, b, f, a, c ]) = true
given f([ f, e, d, c, b, a ]) = true
given f([ c, b, f, a, d, e ]) = true
given f([ a, c, f, b, e, d ]) = true
given f([ anything else ]) = false
the expected output for p_accepted is [c, b, f, a, d, e]
it is accepted because f(p_accepted) returns true and no other permutation of l ranks the item 'c' as high. item 'c' is the most preferred by the user since it has index 0
Implementations in pseudo code or any language are accepted.
[EDIT]
Clarifications
list p will always contain all elements of list l
list l items can only be compared by identity, i.e.: by reference
so an item in list p can be found in list l by l[i] == p[j]
list l items cannot always be compared like in the example where a compare function c might determine that a < b i.e.: c('a', 'b') = 1.
[EDIT 2]
To understand preferences better
Imagine Alice and Bob being forced to do 4 tasks together at the same time in order. [task a, task b, task c, task d].
Alice has one preferred order for doing the tasks [a,b,c,d]. Bob has two preferred orders for doing the tasks [a,c,b,d], [a,d,b,c]. If you are Alice, the function f would return true only for [a,c,b,d] and [a,d,b,c] which are Bob's preferences, since both like to do task a first p_accepted should start with a.
Note that this is an analogy function f does not accept permutations based on multiple user's order preference.

Prolog, 3 in a row, any direction

I'm trying to write a procedure in prolog where a list might look something like this:
threeInRow(x,[b, b, a, threeInRow(x,[b, d, a,
c, a, b, c, d, b,
a, d, d]) b, d, a])
Both of these would return true. The list always contains 9 elements and can be any of character ranging from a-d.
threeInRow(x,[b, b, j
c, j, b,
j, d, d])
Would however return false, because it's not a character ranging from a-d.
If you want to verify only length of the list (9) and allowed elements:
item_allowed(Item) :-
member(Item, [a, b, c, d]).
threeInRow(List) :-
length(List, 9),
maplist(item_allowed, List).

Create an order from several incomplete orders

Here is the motivation and how it should behave, but I need a help how to implement it.
I have several (typically) incomplete orders given as ordered values, for ex.:
1. A, C, D
2. D, E
3. X, B
4. B, C
5. C, F
6. C, A
and the resulting order should be:
A, X, B, C, D, E, F or A, X, B, C, F, D, E or A, X, B, C, D, F, E
The idea behind it is sort the result based on first seen order. I will try explain it on the example in steps:
order A, C, D
D, E - D seen, so add E after D, so order A, C, D, E
X, B - no value seen yet, so we can not determine the order now, so create 2nd temporary order X, B
B, C - C already seen, so order A, B, C, D, E
and 2nd order can be merged via B, so A, X, B, C, D, E
C, F - C see, so order A, X, B, C, D, E, F
C, A - ignore, both values are part of already defined order (by first incomplete order A, C, D)
But what if an additional incomplete order F, D or F, E will be part (added to the end) of the input? The step-by-step mental algorithm will fail - F was already placed.
How can the idea be implemented, any idea?

GOP Reassemble and display order

How do you display the following transition in MPEG bit code?
I, P, B, B, P, B, B, B, I, P, B, B, B, P, B, P
Thank you
Usually it will be displayed as
I, B, B, P, B, B, B, P, I, B, B, B, P, B, P, P

using prolog to generate sentences

Consider the following list of states:
[Sin,S2,S3,...,Sout]
and following rules:
it is possible to go back from S(n) to S(n-1) if there is such
S(n-1)
it is not possible to go back from S(out)
a sentence always begins with S(in) and ends with S(out)
I would like to have a rule that could be activated like this:
?- sentence(X, backs)
in which 'backs' means how many times a "back" is allowed.
For this list [a,b,c,d]
?- sentence(x, 2)
would generate:
[a,b,c,d] %no backs
[a,b,a,b,c,d] %one back
[a,b,c,b,c,d] %from d we cannot go back
[a,b,a,b,c,b,c,d] %two backs
[a,b,c,b,a,b,c,d] %two backs
Here's something that seems to be working:
sentence( [A|B], N, [A|X]) :- B=[_|_] -> sentence(B,[A],N,X)
; B = X.
sentence( B, _, 0, B). % no more moves back left
sentence( [B,C], _, N, [B,C]):- N>0. % no going back from end node
sentence( [B|C], A, N, [B|X]):- N>0, C=[_|_],
sentence( C, [B|A], N, X). $ fore
sentence( [B|C], [A|D], N, [B|X]):- N>0, C=[_|_], N1 is N-1,
sentence( [A,B|C], D, N1, X). $ aft
Running it gives me
23 ?- sentence([a,b,c,d],2,X).
X = [a, b, c, d] ;
X = [a, b, c, b, c, d] ;
X = [a, b, c, b, c, b, c, d] ;
X = [a, b, c, b, a, b, c, d] ;
X = [a, b, a, b, c, d] ;
X = [a, b, a, b, c, b, c, d] ;
X = [a, b, a, b, a, b, c, d] ;
No

Resources