2017-06-05 3 views
0

je le dictionnaire suivant:Obtenez tous les sous-ensembles d'un dictionnaire Python avec des restrictions

intervals = {'param1': [0, 1], 
      'param2_hi': [4, 5, 6, 7, 8, 9], 
      'param2_lo': [0, 1, 2, 3, 4, 5], 
      'param3_hi': [9, 10, 11, 12, 13, 14, 15], 
      'param3_lo': [5, 6, 7, 8, 9, 10], 
      'param4': [0, 1], 
      'param5_hi': [4, 5, 6, 7, 8, 9], 
      'param5_lo': [0, 1, 2, 3, 4, 5]} 

Comment puis-je créer tous les sous-ensembles possibles de ce dictionnaire où je dois avoir exactement un de chaque numéro x pour « paramx »? Cela signifie que je ne peux avoir qu'une entrée pour param1 (_lo ou _hi), une entrée pour param2 (_lo ou _hi), et ainsi de suite, et que chaque sous-ensemble doit inclure tous les paramx qui n'ont pas de _lo ou _hi.

Voici deux sous-ensembles possibles:

subset_one = {'param1': [0, 1], 
       'param2_hi': [4, 5, 6, 7, 8, 9], 
       'param3_hi': [9, 10, 11, 12, 13, 14, 15], 
       'param4': [0, 1], 
       'param5_hi': [4, 5, 6, 7, 8, 9]} 

subset_two = {'param1': [0, 1], 
       'param2_lo': [0, 1, 2, 3, 4, 5], 
       'param3_lo': [5, 6, 7, 8, 9, 10], 
       'param4': [0, 1], 
       'param5_lo': [0, 1, 2, 3, 4, 5]} 

# Example of mixed '_hi' and '_lo' intervals 
subset_three = {'param1': [0, 1], 
       'param2_lo': [0, 1, 2, 3, 4, 5], 
       'param3_hi': [9, 10, 11, 12, 13, 14, 15], 
       'param4': [0, 1], 
       'param5_lo': [0, 1, 2, 3, 4, 5]} 

... 

Note: Je veux préserver la clé, des paires de valeurs. Edit: Ajout de subset_three pour montrer la possibilité d'avoir des intervalles mixés '_lo' et '_hi'.

+0

Est-ce que ce sont les seules clés que vous auriez? –

+0

Est-ce une liste finie de paramètres, sont-ils leurs vrais noms et sont-ils toujours suffixés avec un nombre dans l'ordre croissant? – zwer

+0

Il pourrait y avoir plus (en fonction des différentes exécutions de mon programme), mais les clés seront toujours de la forme paramx, paramx_lo, paramx_hi où x est un nombre entier. –

Répondre

1

Je pense que les deux collections.defaultdict et itertools.product seront utiles ici. Tout d'abord, construisez un pool qui trie les clés en fonction de ce qu'elles commencent. Ensuite, construisez le produit cartésien de ces cases.

from collections import defaultdict 
from itertools import product 

pool = defaultdict(list) 
for key in intervals: 
    base = key.split('_')[0] 
    pool[base].append(key) 

subsets = [{key: intervals[key] for key in keys} for keys in product(*pool.values())] 

# {'param2_lo': [0, 1, 2, 3, 4, 5], ... , 'param1': [0, 1]} 
# {'param5_lo': [0, 1, 2, 3, 4, 5], ..., 'param2_hi': [4, 5, 6, 7, 8, 9]} 
# and so on... 
+0

'itertools.product() 'retournera un itérateur avec des éléments de tuple qui échoueront dans votre compréhension des dictées car' interval's contiennent des clés individuelles. Vous devez double-boucle comme: 'sous-ensembles = [{clé: intervalles [touche] pour clé dans les touches} pour les clés dans le produit (* pool.values ​​())]' – zwer

+0

@zwer mis à jour, merci –

2

Dans la plupart des cas simple, vous pouvez utiliser les dict compréhensions suivantes:

subset_1 = {k:v for k,v in intervals.items() if k.endswith('_hi') or not k.endswith('_lo')} 
subset_2 = {k:v for k,v in intervals.items() if k.endswith('_lo') or not k.endswith('_hi')} 

print(subset_1) 
print(subset_2) 

La sortie:

{'param3_hi': [9, 10, 11, 12, 13, 14, 15], 'param1': [0, 1], 'param2_hi': [4, 5, 6, 7, 8, 9], 'param4': [0, 1], 'param5_hi': [4, 5, 6, 7, 8, 9]} 
{'param2_lo': [0, 1, 2, 3, 4, 5], 'param1': [0, 1], 'param3_lo': [5, 6, 7, 8, 9, 10], 'param4': [0, 1], 'param5_lo': [0, 1, 2, 3, 4, 5]} 
+0

Il pourrait y avoir une combinaison de valeurs hautes et basses. C'est seulement que je dois avoir un de chaque paramètre numéroté. –

+0

@ToddYoung, pouvez-vous mettre à jour votre question avec des conditions étendues et élaborées et la sortie désirée? – RomanPerekhrest

+0

Juste ajouté 'subset_three', un exemple où nous pourrions avoir un mélange d'intervalles '_lo' et '_hi'. –

1

Je crois que vous voulez itertools.product appliqué aux cinq ensembles de choix dans vos paramètres:

choices = [ 
    ['param1'], 
    ['param2_lo', 'param2_hi'], 
    ['param3_lo', 'param3_hi'], 
    ['param4'], 
    ['param5_lo', 'param5_hi'] 
] 

for permute in itertools.product(*choices): 
    .... 

Est-ce assez pour vous y aller?

+1

Vous auriez besoin utiliser '(* choix)', je pense. – DSM

0

Je pense que le meilleur outil à utiliser est itertools.product, une solution serait:

intervals = {'param1': [0, 1], 
      'param2_hi': [4, 5, 6, 7, 8, 9], 
      'param2_lo': [0, 1, 2, 3, 4, 5], 
      'param3_hi': [9, 10, 11, 12, 13, 14, 15], 
      'param3_lo': [5, 6, 7, 8, 9, 10], 
      'param4': [0, 1], 
      'param5_hi': [4, 5, 6, 7, 8, 9], 
      'param5_lo': [0, 1, 2, 3, 4, 5]} 


import itertools 

def get_subsets(intervals): 

    params_list = set(key.split('_')[0] for key in intervals.keys()) 

    list_keys = [[x for x in intervals.keys() if x.startswith(param)] for param in params_list] 

    subsets = [{x : intervals[x] for x in sublist} for sublist in itertools.product(*list_keys)] 

    return subsets 

get_subsets(intervals) 

# [{'param2_lo': [0, 1, 2, 3, 4, 5], 'param3_hi': [9, 10, 11, 12, 13, 14, 15], 'param5_lo': [0, 1, 2, 3, 4, 5], 'param1': [0, 1], 'param4': [0, 1]}, {'param2_lo': [0, 1, 2, 3, 4, 5], 'param3_hi': [9, 10, 11, 12, 13, 14, 15], 'param1': [0, 1], 'param4': [0, 1], 'param5_hi': [4, 5, 6, 7, 8, 9]}, ... 
0

Vous pouvez utiliser groupby et product du module itertools comme cet exemple afin de répertorier toutes les combinaisons possibles:

from itertools import groupby, product 

intervals = {'param1': [0, 1], 
      'param2_hi': [4, 5, 6, 7, 8, 9], 
      'param2_lo': [0, 1, 2, 3, 4, 5], 
      'param3_hi': [9, 10, 11, 12, 13, 14, 15], 
      'param3_lo': [5, 6, 7, 8, 9, 10], 
      'param4': [0, 1], 
      'param5_hi': [4, 5, 6, 7, 8, 9], 
      'param5_lo': [0, 1, 2, 3, 4, 5]} 


sub = [] 

for _,v in groupby(sorted(intervals.keys()), lambda x: x[5]): 
    # Or: 
    # sub.append(list(v)) 
    sub.append(sorted(list(v))) 


for k in product(*sub): 
    print({j:intervals[j] for j in k}) 
    print("------") 

sortie:

{'param1': [0, 1], 'param3_hi': [9, 10, 11, 12, 13, 14, 15], 'param2_hi': [4, 5, 6, 7, 8, 9], 'param5_hi': [4, 5, 6, 7, 8, 9], 'param4': [0, 1]} 
------ 
{'param1': [0, 1], 'param3_hi': [9, 10, 11, 12, 13, 14, 15], 'param2_hi': [4, 5, 6, 7, 8, 9], 'param5_lo': [0, 1, 2, 3, 4, 5], 'param4': [0, 1]} 
------ 
{'param1': [0, 1], 'param2_hi': [4, 5, 6, 7, 8, 9], 'param5_hi': [4, 5, 6, 7, 8, 9], 'param3_lo': [5, 6, 7, 8, 9, 10], 'param4': [0, 1]} 
------ 
{'param1': [0, 1], 'param2_hi': [4, 5, 6, 7, 8, 9], 'param3_lo': [5, 6, 7, 8, 9, 10], 'param5_lo': [0, 1, 2, 3, 4, 5], 'param4': [0, 1]} 
------ 
.... 
------ 

{'param4': [0, 1], 'param1': [0, 1], 'param5_hi': [4, 5, 6, 7, 8, 9], 'param3_lo': [5, 6, 7, 8, 9, 10], 'param2_lo': [0, 1, 2, 3, 4, 5]} 
------ 
{'param4': [0, 1], 'param1': [0, 1], 'param5_lo': [0, 1, 2, 3, 4, 5], 'param3_lo': [5, 6, 7, 8, 9, 10], 'param2_lo': [0, 1, 2, 3, 4, 5]} 
------