0

I have a list if items/ tuples which contain sets like this:

a_list = [(a, {x}), (b, {y}), (c, {y,z}), (d, {y,z}), (e, {x,y}), (f, {x,y,z})]

And a sample pattern:

pattern = {x,y}

Given a number of draws i would like to generate a sequence of items from a_list that fits the pattern most. The pattern shall be fulfilled with the second part of the tuple, the set.

Example:

A result with draws = 2 could be:

result = [(a, {x}), (b, {y})]
# x, y

or

result = [(e, {x,y}), (a, {x})]
# x, y

or

result = [(e, {x,y}), (b, {y})]
# x, y

Both cases fulfill the pattern {x,y} within 2 draws.

A result with draws = 1 could only be:

result = (e, {x,y})
# x, y

since there is only one draw to fulfill the pattern and only item e matches the pattern totally.

A result with draws = 7 could be:

result = [(a, {x}), (b, {y}), (e, {x,y}), (f, {x,y,z}), (c, {y,z})]
# x, y, x, y, x, y, y

Can such a function be accomplished and if, how?

Thanks for your help!

Muffin

Raggamuffin
  • 699
  • 1
  • 6
  • 19
  • what do you mean by `overhead` and `draw`? is `draw` the *expected* number of {x,y} has to be in the final sets? – TuanDT Dec 16 '16 at 13:58
  • "draw" is the number of times an element from the a_list is taken and evaluated against the pattern. – Raggamuffin Dec 16 '16 at 14:23
  • I removed the overhead this just complicates the thought. With overhead i mean when i take 7 items from the list and the pattern has 2 items, ideally the pattern is fit 3 times and the last draw only fits a part of the pattern. that part i call overhead. – Raggamuffin Dec 16 '16 at 14:32
  • so if `draw = 3`, and your list has 10 items, you could do 3*10 = 30 comparisons in total? or does it mean that you can only do 3 comparisons in total regardless of how many items there are in the list? – TuanDT Dec 16 '16 at 14:35
  • the first - in general it means that you try 3 times to get an approriate item from the list to fulfill the pattern requirements – Raggamuffin Dec 16 '16 at 15:02

1 Answers1

0

If what i understood from your question and your comments is correct, the function below should give you the right output/print and should be equal to what you've expected in your question.

Here is my solution

from itertools import groupby
from random import randint

a_list = [
    ('a', {'x'}), ('b', {'y'}), 
    ('c', {'y','z'}), ('d', {'y','z'}),
    ('e', {'x','y'}), ('f', {'x','y','z'})
]

pattern = {'x', 'y'}


def seq_gen(a=[], pattern=set(), draws=0):
    single, multi = [], []
    
    for i in a:
        if len(i[1]) == 1:
            single.append(i)
        else:
            multi.append(i)
    
    final = [
       j for j in single
       if list(pattern)[0] in j[1]
       or list(pattern)[1] in j[1]
    ]
    final += [j for j in multi if pattern == j[1]]
    
    if draws == 1:
        for i in final:
            if len(i[1]) == 2:
                # for better use, return a list not a tuple
                return "draw(1) => {0}".format([i])
                
    if draws > len(final):
        k, f = list(), tuple()
        for _, v in groupby(a, lambda x: x[1]):
            k += list(v)[0]
                    
        return "draw({0}) => {1}".format(
            draws,
            [tuple(k[x:x+2]) for x in range(0,len(k), 2)]
        )
        
    if draws == len(final):
        return "draw({0}) => {1}".format(draws, final)
    
    else:
        aa = []
        while len(aa) != 2:
            element = final[randint(0, len(final) -1)]
            if element not in aa:
                aa.append(element)
        return "draw({0}) => {1}".format(draws, aa)
    
for i in range(1,8):
    print(seq_gen(a_list, pattern, i))

Output:

draw(1) => [('e', {'x', 'y'})]
draw(2) => [('e', {'x', 'y'}), ('a', {'x'})]
draw(3) => [('a', {'x'}), ('b', {'y'}), ('e', {'x', 'y'})]
draw(4) => [('a', {'x'}), ('b', {'y'}), ('c', {'z', 'y'}), ('e', {'x', 'y'}), ('f', {'x', 'z', 'y'})]
draw(5) => [('a', {'x'}), ('b', {'y'}), ('c', {'z', 'y'}), ('e', {'x', 'y'}), ('f', {'x', 'z', 'y'})]
draw(6) => [('a', {'x'}), ('b', {'y'}), ('c', {'z', 'y'}), ('e', {'x', 'y'}), ('f', {'x', 'z', 'y'})]
draw(7) => [('a', {'x'}), ('b', {'y'}), ('c', {'z', 'y'}), ('e', {'x', 'y'}), ('f', {'x', 'z', 'y'})]

PS: Don't hesitate to return your feedbacks. If there is something wrong i'll try to fix it with your new queries.

Chiheb Nexus
  • 9,104
  • 4
  • 30
  • 43
  • 1
    instead of transforming it to a list, use set operation like intersection, also change your default from `{}` to `set()` or better yet `frozenset()` because `{}` produce a dictionary – Copperfield Dec 16 '16 at 19:32
  • Yes you're right. But i tried to produce the same output like the OP want to have. Also this is not the complete solution. I'm waiting the OP feedbacks because i didn't got all the queries between 2 and 7 and how to deal with them. – Chiheb Nexus Dec 16 '16 at 19:36