0

I have a set of nested lists which can be seperated in three groups:

  • A (subelements are disjunction, line colors GREEN), e.g.

    listA = {
    ‘a1’: ['b1', 'a2'],
    ‘a2’: ['c1', 'c2']
     }
    
  • B (subelements are ordered conjunction, line colors ORANGE), e.g.

    listB = {
    ‘b1’: ['c4', 'c5', 'c7'],
    ‘b2’:['c3', 'b1']
     }
    
  • C (final elements - leaf nodes)

The function combinations itereates through the nested lists and returns all possible combinations (which at the end only contains of elements of type C, so leaf nodes). The function write_nodes helps to write the nodes with colored lines. The call write_nodes('task', inputlist) is for creating the init node:

def write_nodes(node, subnotes):
    for k in subnotes:
        if node in type_a:
            text_file.write("{} -> {} [color=\"green\"]\n".format(node, k)) 
        elif (node in type_b) or (node is 'task'):
            text_file.write("{} -> {} [color=\"orange\"]\n".format(node, k))

write_nodes('task', inputlist)

def combinations(actions):
    if len(actions)==1:
        action= actions[0]
        if action not in type_c:
            root = action
        try:
            actions= type_a[action]
            write_nodes(root, actions)
        except KeyError:
            try:
                actions= type_b[action]
                write_nodes(root, actions)
            except KeyError:
                #action is of type C, the only possible combination is itself
                yield actions
            else:
                #action is of type B (conjunction), combine all the actions
                for combination in combinations(actions):
                    yield combination
        else:
            #action is of type A (disjunction), generate combinations for each action
            for action in actions:
                for combination in combinations([action]):
                    yield combination
    else:
        #generate combinations for the first action in the list
        #and combine them with the combinations for the rest of the list
        action= actions[0]
        for combination in combinations(actions[1:]):
            for combo in combinations([action]):
                yield combo + combination

Example input (ordered conjunction):

['a1', 'b2', 'c6']

Example result:

['c4', 'c5', 'c7', 'c3', 'c4', 'c5', 'c7', 'c6']
['c1', 'c3', 'c4', 'c5', 'c7', 'c6']
['c2', 'c3', 'c4', 'c5', 'c7', 'c6']

The result I got from my code: enter image description here corresponding dot file:

task -> a1 [color="orange"]
task -> b2 [color="orange"]
task -> c6 [color="orange"]
b2 -> c3 [color="orange"]
b2 -> b1 [color="orange"]
b1 -> c4 [color="orange"]
b1 -> c5 [color="orange"]
b1 -> c7 [color="orange"]
a1 -> b1 [color="green"]
a1 -> a2 [color="green"]
b1 -> c4 [color="orange"]
b1 -> c5 [color="orange"]
b1 -> c7 [color="orange"]
a2 -> c1 [color="green"]
a2 -> c2 [color="green"]

The result I want (colors are not prior one): enter image description here

Questions:

How can I handle the fact, there there are some duplicated nodes to get a result as mentioned?

Thanks for any help.

eljobso
  • 352
  • 2
  • 6
  • 20
  • Are you familiar with `graphviz` python package? What have you tried? BTW, It is bad practice to use `try/except` for normal program flow. – Ohad Eytan Aug 09 '16 at 09:09
  • 1
    I updated my question, what I have so far. I think _familiar_ is the wrong word, I just know the structure of a dot file. Maybe you can help me, what is a better way to avoid the try/except. – eljobso Aug 09 '16 at 15:02

1 Answers1

2

Duplicate nodes problem

To avoid the duplicate nodes problem you should name each node with a unique name and use a label for the displayed name. For example change:

b2 -> b1 [color="orange"]
b1 -> c4 [color="orange"]
b1 -> c5 [color="orange"]
b1 -> c7 [color="orange"]
a1 -> b1 [color="green"]
b1 -> c4 [color="orange"]
b1 -> c5 [color="orange"]
b1 -> c7 [color="orange"]

to:

b21 [label="b2"]
b11 [label="b1"]
b21 -> b11 [color="orange"]
c41 [label="c4"]
b11 -> c41 [color="orange"]
c51 [label="c5"]
b11 -> c51 [color="orange"]
c71 [label="c7"]
b11 -> c71 [color="orange"]
a11 [label="a2"]
b12 [label="b1"]
a11 -> b12 [color="green"]
c42 [label="c4"]
b12 -> c42 [color="orange"]
c52 [label="c5"]
b12 -> c52 [color="orange"]
c72 [label="c7"]
b12 -> c72 [color="orange"]

Which produce: res

Avoid try/except flow

It's better to use if/else and not try/except for normal program flow. For example instead of:

    try:
        actions= type_a[action]
        write_nodes(root, actions)
    except KeyError:
        #do whatever you do

use:

    actions = type_a.get(action, None) #if the key doesn't exists assign None
    if actions:
        write_nodes(root, actions)
    else:
        #do whatever you do

Graphviz python package

You can use the graphviz python package instead of writing the dot file yourself.

Ohad Eytan
  • 8,114
  • 1
  • 22
  • 31