2016-03-29 7 views
-1

Meine Probe dict ist:generieren alle Kombinationen aus einem verschachtelten Python-Wörterbuch und entmischen sie

sample_dict = { 
    'company': { 
     'employee': { 
      'name': [ 
       {'explore': ["noname"], 
       'valid': ["john","tom"], 
       'boundary': ["aaaaaaaaaa"], 
       'negative': ["$"]}], 
      'age': [ 
       {'explore': [200], 
       'valid': [20,30], 
       'boundary': [1,99], 
       'negative': [-1,100]}], 
      'others':{ 
       'grade':[ 
        {'explore': ["star"], 
        'valid': ["A","B"], 
        'boundary': ["C"], 
        'negative': ["AB"]}]} 
    } 
}} 

Es ist ein „Follow-on“ Frage to->Split python dictionary to result in all combinations of values
Ich mag würde eine getrennte Liste von Kombinationen erhalten wie unten

gültige Kombinationen: [erzeugen nur aus gültigen Liste der Daten]
COMPLETE OUTPUT für VALID KATEGORIE:

{'company': {'employee': {'age': 20}, 'name': 'john', 'others': {'grade': 'A'}}} 
{'company': {'employee': {'age': 20}, 'name': 'john', 'others': {'grade': 'B'}}} 
{'company': {'employee': {'age': 20}, 'name': 'tom', 'others': {'grade': 'A'}}} 
{'company': {'employee': {'age': 20}, 'name': 'tom', 'others': {'grade': 'B'}}} 
{'company': {'employee': {'age': 30}, 'name': 'john', 'others': {'grade': 'A'}}} 
{'company': {'employee': {'age': 30}, 'name': 'john', 'others': {'grade': 'B'}}} 
{'company': {'employee': {'age': 30}, 'name': 'tom', 'others': {'grade': 'A'}}} 
{'company': {'employee': {'age': 30}, 'name': 'tom', 'others': {'grade': 'B'}}} 

Negative Kombinationen: für NEGATIVE Kategorie
Vollständige Ausgabe erwartet [Hier seine bisschen schwierig, da sollte negativen Kombinationen mit „gültig“ Pool mit atleast nur Wert negativ als auch kombiniert werden]:
=> [Grundsätzlich ausgenommen Kombinationen in dem alle Werten gelten - atleast einen Wert in der Kombination aus Gewährleistung negativer Gruppe ist]

{'company': {'employee': {'age': 20}, 'name': 'john', 'others': {'grade': 'AB'}}} 
{'company': {'employee': {'age': -1}, 'name': 'tom', 'others': {'grade': 'A'}}} 
{'company': {'employee': {'age': 100}, 'name': 'john', 'others': {'grade': 'A'}}} 
{'company': {'employee': {'age': 30}, 'name': '$', 'others': {'grade': 'A'}}} 
{'company': {'employee': {'age': 30}, 'name': '$', 'others': {'grade': 'AB'}}} 
{'company': {'employee': {'age': -1}, 'name': '$', 'others': {'grade': 'AB'}}} 
{'company': {'employee': {'age': 100}, 'name': '$', 'others': {'grade': 'AB'}}} 

in der obigen Ausgabe, in der ersten Zeile, Grad wird für negativen Wert aB getestet, indem verbleibenden gesamte gültigen halten. Es ist also nicht notwendig, dasselbe mit einem Alter von 30 zu erzeugen, da die Absicht darin besteht, nur negative Mengen zu testen. Wir können die restlichen Parameter mit gültigen Daten versorgen.


Boundary Kombinationen ist ähnlich gültig -> Kombinationen für alle Werte innerhalb der Grenze Pool nur
erkunden: Ähnlich negativ - mit gültigem Pool mischen und immer atleast einen Wert in allen Kombinationen erkunden.

Beispiel dict - überarbeitete Version

sample_dict2 = { 
    'company': { 
     'employee_list': [ 
      {'employee': {'age': [{'boundary': [1,99], 
            'explore': [200], 
            'negative': [-1,100], 
            'valid': [20, 30]}], 
          'name': [{'boundary': ['aaaaaaaaaa'], 
            'explore': ['noname'], 
            'negative': ['$'], 
            'valid': ['john','tom']}], 
          'others': { 
           'grade': [ 
            {'boundary': ['C'], 
            'explore': ['star'], 
            'negative': ['AB'], 
            'valid': ['A','B']}, 
            {'boundary': ['C'], 
            'explore': ['star'], 
            'negative': ['AB'], 
            'valid': ['A','B']}]}}}, 
      {'employee': {'age': [{'boundary': [1, 99], 
            'explore': [200], 
            'negative': [], 
            'valid': [20, 30]}], 
          'name': [{'boundary': [], 
            'explore': [], 
            'negative': ['$'], 
            'valid': ['john', 'tom']}], 
          'others': { 
           'grade': [ 
            {'boundary': ['C'], 
            'explore': ['star'], 
            'negative': [], 
            'valid': ['A', 'B']}, 
            {'boundary': [], 
            'explore': ['star'], 
            'negative': ['AB'], 
            'valid': ['A', 'B']}]}}} 
     ] 
    } 
} 

Die sample_dict2 enthält eine Liste von dicts. Hier "Mitarbeiter" ist die gesamte Hierarchie ein Listenelement und auch Blattknoten "Note" ist eine Liste
Auch, außer "gültig" und "Grenze" anderen Datensatz kann leer sein - [] und wir müssen sie auch behandeln .
VALID ZUSAMMEN wird wie sein

{'company': {'employee_list':[{'employee': {'age': 20}, 'name': 'john', 'others': {'grade': ['A','A']}},{'employee': {'age': 1}, 'name': 'john', 'others': {'grade': ['A','A']}}]}} 
{'company': {'employee_list':[{'employee': {'age': 20}, 'name': 'john', 'others': {'grade': ['A','A']}},{'employee': {'age': 1}, 'name': 'john', 'others': {'grade': ['A','B']}}]}} 
{'company': {'employee_list':[{'employee': {'age': 20}, 'name': 'john', 'others': {'grade': ['A','A']}},{'employee': {'age': 1}, 'name': 'tom', 'others': {'grade': ['A','A']}}]}} 
{'company': {'employee_list':[{'employee': {'age': 20}, 'name': 'john', 'others': {'grade': ['A','A']}},{'employee': {'age': 1}, 'name': 'tom', 'others': {'grade': ['A','B']}}]}} 
{'company': {'employee_list':[{'employee': {'age': 20}, 'name': 'john', 'others': {'grade': ['A','B']}},{'employee': {'age': 1}, 'name': 'john', 'others': {'grade': ['A','A']}}]}} 
{'company': {'employee_list':[{'employee': {'age': 20}, 'name': 'john', 'others': {'grade': ['A','B']}},{'employee': {'age': 1}, 'name': 'john', 'others': {'grade': ['A','B']}}]}} 
{'company': {'employee_list':[{'employee': {'age': 20}, 'name': 'john', 'others': {'grade': ['A','B']}},{'employee': {'age': 1}, 'name': 'tom', 'others': {'grade': ['A','A']}}]}} 
{'company': {'employee_list':[{'employee': {'age': 20}, 'name': 'john', 'others': {'grade': ['A','B']}},{'employee': {'age': 1}, 'name': 'tom', 'others': {'grade': ['A','B']}}]}} 

sowie Kombinationen von Alter = 30 und name = tom in Mitarbeiter Index 0

+0

Ich verstehe Ihre Anforderungen nicht. Was bedeutet es, dass eine negative Kombination gültige Pools mit mindestens einem negativen Wert kombinieren sollte? Meinst du, dass Kombinationen, die einen Wert in der negativen Klasse enthalten, * genau zwei * Werte aus der negativen Klasse enthalten sollten? Oder dass sie in gerader Zahl sein müssen? Oder etwas anderes? Ich schlage vor, Sie beschreiben genauer Ihre genauen Anforderungen. Darüber hinaus kann es sinnvoll sein, ein * vollständiges * Beispiel für die Ausgabe anzugeben, damit es als Testfall verwendet werden kann. – Bakuriu

+0

Es ist im Grunde für negative Tests. Das heißt, die für die negative Kategorie zu trennenden Kombinationen können auch Werte aus der gültigen Liste von Daten annehmen, aber nicht alle Eingaben können gültig sein, dh mindestens einer der Werte in der bestimmten generierten Kombination sollte negativ sein die vollständige Ausgabe. – Suren

+0

@Bakuriu aktualisiert die Frage mit vollständiger Ausgabe und mehr Klarstellung. Bitte lassen Sie mich wissen, wenn mir noch etwas fehlt. Danke – Suren

Antwort

4
import itertools 

def generate_combinations(thing, positive="valid", negative=None): 

    """ Generate all possible combinations, walking and mimicking structure of "thing" """ 

    if isinstance(thing, dict): # if dictionary, distinguish between two types of dictionary 
     if positive in thing: 
      return thing[positive] if negative is None else [thing[positive][0]] + thing[negative] 
     else: 
      results = [] 
      for key, value in thing.items(): # generate all possible key: value combinations 
       subresults = [] 
       for result in generate_combinations(value, positive, negative): 
        subresults.append((key, result)) 
       results.append(subresults) 
      return [dict(result) for result in itertools.product(*results)] 

    elif isinstance(thing, list) or isinstance(thing, tuple): # added tuple just to be safe 
     results = [] 
     for element in thing: # generate recursive result sets for each element of list 
      for result in generate_combinations(element, positive, negative): 
       results.append(result) 
     return results 

    else: # not a type we know how to handle 
     raise TypeError("Unexpected type") 


def generate_invalid_combinations(thing): 

    """ Generate all possible combinations and weed out the valid ones """ 

    valid = generate_combinations(thing) 

    return [result for result in generate_combinations(thing, negative='negative') if result not in valid] 


def generate_boundary_combinations(thing): 

    """ Generate all possible boundary combinations """ 

    return generate_combinations(thing, positive="boundary") 


def generate_explore_combinations(thing): 

    """ Generate all possible explore combinations and weed out the valid ones """ 

    valid = generate_combinations(thing) 

    return [result for result in generate_combinations(thing, negative='explore') if result not in valid] 

Aufruf generate_combinations(sample_dict) Rückkehr:

[ 
{'company': {'employee': {'age': 20, 'name': 'john', 'others': {'grade': 'A'}}}}, 
{'company': {'employee': {'age': 20, 'name': 'john', 'others': {'grade': 'B'}}}}, 
{'company': {'employee': {'age': 20, 'name': 'tom', 'others': {'grade': 'A'}}}}, 
{'company': {'employee': {'age': 20, 'name': 'tom', 'others': {'grade': 'B'}}}}, 
{'company': {'employee': {'age': 30, 'name': 'john', 'others': {'grade': 'A'}}}}, 
{'company': {'employee': {'age': 30, 'name': 'john', 'others': {'grade': 'B'}}}}, 
{'company': {'employee': {'age': 30, 'name': 'tom', 'others': {'grade': 'A'}}}}, 
{'company': {'employee': {'age': 30, 'name': 'tom', 'others': {'grade': 'B'}}}} 
] 

Aufruf generate_invalid_combinations(sample_dict) Rückkehr:

[ 
{'company': {'employee': {'age': 20, 'name': 'john', 'others': {'grade': 'AB'}}}}, 
{'company': {'employee': {'age': 20, 'name': '$', 'others': {'grade': 'A'}}}}, 
{'company': {'employee': {'age': 20, 'name': '$', 'others': {'grade': 'AB'}}}}, 
{'company': {'employee': {'age': -1, 'name': 'john', 'others': {'grade': 'A'}}}}, 
{'company': {'employee': {'age': -1, 'name': 'john', 'others': {'grade': 'AB'}}}}, 
{'company': {'employee': {'age': -1, 'name': '$', 'others': {'grade': 'A'}}}}, 
{'company': {'employee': {'age': -1, 'name': '$', 'others': {'grade': 'AB'}}}}, 
{'company': {'employee': {'age': 100, 'name': 'john', 'others': {'grade': 'A'}}}}, 
{'company': {'employee': {'age': 100, 'name': 'john', 'others': {'grade': 'AB'}}}}, 
{'company': {'employee': {'age': 100, 'name': '$', 'others': {'grade': 'A'}}}}, 
{'company': {'employee': {'age': 100, 'name': '$', 'others': {'grade': 'AB'}}}} 
] 

Aufruf generate_boundary_combinations (sample_dict) liefert:

[ 
{'company': {'employee': {'age': 1, 'name': 'aaaaaaaaaa', 'others': {'grade': 'C'}}}}, 
{'company': {'employee': {'age': 99, 'name': 'aaaaaaaaaa', 'others': {'grade': 'C'}}}} 
] 

Aufruf generate_explore_combinations (sample_dict) kehrt: die gleiche wie vor

[ 
{'company': {'employee': {'age': 20, 'name': 'john', 'others': {'grade': 'star'}}}}, 
{'company': {'employee': {'age': 20, 'name': 'noname', 'others': {'grade': 'A'}}}}, 
{'company': {'employee': {'age': 20, 'name': 'noname', 'others': {'grade': 'star'}}}}, 
{'company': {'employee': {'age': 200, 'name': 'john', 'others': {'grade': 'A'}}}}, 
{'company': {'employee': {'age': 200, 'name': 'john', 'others': {'grade': 'star'}}}}, 
{'company': {'employee': {'age': 200, 'name': 'noname', 'others': {'grade': 'A'}}}}, 
{'company': {'employee': {'age': 200, 'name': 'noname', 'others': {'grade': 'star'}}}} 
] 

REVISED SOLUTION (überarbeitet Problem entsprechen) sind

import itertools 
import random 

def generate_combinations(thing, positive="valid", negative=None): 

    """ Generate all possible combinations, walking and mimicking structure of "thing" """ 

    if isinstance(thing, dict): # if dictionary, distinguish between two types of dictionary 
     if positive in thing: 
      if negative is None: 
       return thing[positive] # here it's OK if it's empty 
      elif thing[positive]: # here it's not OK if it's empty 
       return [random.choice(thing[positive])] + thing[negative] 
      else: 
       return [] 
     else: 
      results = [] 
      for key, value in thing.items(): # generate all possible key: value combinations 
       results.append([(key, result) for result in generate_combinations(value, positive, negative)]) 
      return [dict(result) for result in itertools.product(*results)] 

    elif isinstance(thing, (list, tuple)): # added tuple just to be safe (thanks Padraic!) 
     # generate recursive result sets for each element of list 
     results = [generate_combinations(element, positive, negative) for element in thing] 
     return [list(result) for result in itertools.product(*results)] 

    else: # not a type we know how to handle 
     raise TypeError("Unexpected type") 


def generate_boundary_combinations(thing): 

    """ Generate all possible boundary combinations """ 

    valid = generate_combinations(thing) 

    return [result for result in generate_combinations(thing, negative='boundary') if result not in valid] 

generate_invalid_combinations() und generate_explore_combinations(). Subtile Unterschiede:

Statt das erste Element aus dem gültigen Array in einer negativen Bewertung zu greifen, greift es jetzt ein zufälliges Element aus dem gültigen Array.

Werte für Elemente wie 'age': [30] wieder als Listen wie das ist, wie sie angegeben wurden:

'age': [{'boundary': [1, 99], 
    'explore': [200], 
    'negative': [-1, 100], 
    'valid': [20, 30]}], 

Wenn Sie stattdessen 'age': 30 wie die früheren Ausgabe Beispiele wollen, dann entsprechend der Definition ändern:

'age': {'boundary': [1, 99], 
    'explore': [200], 
    'negative': [-1, 100], 
    'valid': [20, 30]}, 

Die Begrenzungseigenschaft wird jetzt wie einer der "negativen" Werte behandelt.

nur als Referenz, ich habe nicht alle Ausgänge dieses Mal zu generieren: Aufruf generate_combinations(sample_dict2) liefert Ergebnisse wie:

[ 
{'company': {'employee_list': [{'employee': {'name': ['john'], 'others': {'grade': ['A', 'A']}, 'age': [20]}}, {'employee': {'name': ['john'], 'others': {'grade': ['A', 'A']}, 'age': [20]}}]}}, 
{'company': {'employee_list': [{'employee': {'name': ['john'], 'others': {'grade': ['A', 'A']}, 'age': [20]}}, {'employee': {'name': ['john'], 'others': {'grade': ['A', 'A']}, 'age': [30]}}]}}, 
{'company': {'employee_list': [{'employee': {'name': ['john'], 'others': {'grade': ['A', 'A']}, 'age': [20]}}, {'employee': {'name': ['john'], 'others': {'grade': ['A', 'B']}, 'age': [20]}}]}}, 
{'company': {'employee_list': [{'employee': {'name': ['john'], 'others': {'grade': ['A', 'A']}, 'age': [20]}}, {'employee': {'name': ['john'], 'others': {'grade': ['A', 'B']}, 'age': [30]}}]}}, 
{'company': {'employee_list': [{'employee': {'name': ['john'], 'others': {'grade': ['A', 'A']}, 'age': [20]}}, {'employee': {'name': ['john'], 'others': {'grade': ['B', 'A']}, 'age': [20]}}]}}, 
... 
{'company': {'employee_list': [{'employee': {'name': ['tom'], 'others': {'grade': ['B', 'B']}, 'age': [30]}}, {'employee': {'name': ['tom'], 'others': {'grade': ['A', 'B']}, 'age': [30]}}]}}, 
{'company': {'employee_list': [{'employee': {'name': ['tom'], 'others': {'grade': ['B', 'B']}, 'age': [30]}}, {'employee': {'name': ['tom'], 'others': {'grade': ['B', 'A']}, 'age': [20]}}]}}, 
{'company': {'employee_list': [{'employee': {'name': ['tom'], 'others': {'grade': ['B', 'B']}, 'age': [30]}}, {'employee': {'name': ['tom'], 'others': {'grade': ['B', 'A']}, 'age': [30]}}]}}, 
{'company': {'employee_list': [{'employee': {'name': ['tom'], 'others': {'grade': ['B', 'B']}, 'age': [30]}}, {'employee': {'name': ['tom'], 'others': {'grade': ['B', 'B']}, 'age': [20]}}]}}, 
{'company': {'employee_list': [{'employee': {'name': ['tom'], 'others': {'grade': ['B', 'B']}, 'age': [30]}}, {'employee': {'name': ['tom'], 'others': {'grade': ['B', 'B']}, 'age': [30]}}]}} 
] 
+0

Vielen Dank für die Antwort, wird überprüft und auf Sie zurückkommen. – Suren

+0

isinstance cna nehme ein Tupel von args 'isinstance (sache, (liste, tuple))' –

+0

@cdlane, Dieser Code funktioniert super !! Kannst du es bitte mit der Liste von Dicts und leeren Arrays umgehen? Aktualisierte Frage mit überarbeiteter Eingabe dict => sample_dict2. Danke für deine wundervolle Arbeit! – Suren

0

dies eine offene Nest einer Frage Hornissen ist.

  1. Blick auf dem White Paper für Agitar andere Werkzeuge von Agitar zu sehen, ob das, was Sie denken.

  2. Betrachten Sie Knuths Arbeit an combinationals. Es ist eine harte Lektüre.

  3. Sie sollten nur einen rekursiven Abstiegsgenerator schreiben, der 'yield' verwendet.

Verwandte Themen