2016-09-21 1 views
2

J'ai une liste de numéros:Comment puis-je trouver une valeur relative à l'endroit où se trouve une liste dans ma liste en Python?

Data = [0,2,0,1,2,1,0,2,0,2,0,1,2,0,2,1,1,...] 

et moi avons une liste de tuples de deux, ce qui est toutes les combinaisons possibles des numéros individuels ci-dessus:

Combinations = [(0,0),(0,1),(0,2),(1,0),(1,1),(1,2),(2,0),(2,1),(2,2)] 

Je veux essayer de trouver où chaque élément dans Combinations apparaît dans Data et ajoute la valeur après chaque occurrence à une autre liste.

Par exemple, pour (0,2) je veux faire une liste [0,0,0,1] car ce sont les valeurs qui tombent immédiatement après (0,2) dans Data.

Jusqu'à présent, j'ai:

any(Data[i:i+len(CurrentTuple)] == CurrentTuple for i in xrange(len(Data)-len(CurrentTuple)+1)) 

CurrentTuple est Combinations.pop(). Le problème est que cela me donne seulement un booléen de savoir si le CurrentTuple se produit dans les données. Ce dont j'ai vraiment besoin, c'est la valeur après chaque occurrence dans Data.

Est-ce que quelqu'un a des idées sur la façon dont cela peut être résolu? Merci!

+0

Si vous avez besoin de quelque chose de plus rapide (j'imagine que si vous travaillez avec markov-chain c'est le cas) vérifiez aussi ma réponse ci-dessous ... Éviter 'append' rend la génération de liste beaucoup plus rapide. –

Répondre

0

Vous pouvez utiliser un dict pour regrouper les données pour voir où/si des terres de peigne dans la liste originale remonte la fermeture éclair paires:

it1, it2 = iter(Data), iter(Data) 
next(it2) 

Combinations = [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)] 

d = {c: [] for c in Combinations} 
ind = 2 
for i, j in zip(it1, it2): 
    if (i, j) in d and ind < len(Data): 
     d[(i, j)].append(Data[ind]) 
    ind += 1 
print(d) 

qui vous donnerait:

{(0, 1): [2, 2], (1, 2): [1, 0], (0, 0): [], (2, 1): [0, 1], (1, 1): [2], (2, 0): [1, 2, 1, 2], (2, 2): [], (1, 0): [2], (0, 2): [0, 0, 0, 1]} 

Vous pourriez aussi le faire en sens inverse:

from collections import defaultdict 

it1, it2 = iter(Data), iter(Data) 
next(it2) 
next_ele_dict = defaultdict(list) 
data_iter = iter(Data[2:]) 
for ind, (i, j) in enumerate(zip(it1, it2)): 
    if ind < len(Data) -2: 
     next_ele_dict[(i, j)].append(next(data_iter)) 

def next_ele(): 
    for comb in set(Combinations): 
     if comb in next_ele_dict: 
      yield comb, next_ele_dict[comb] 

print(list(next_ele())) 

qui vous donnerait:

[((0, 1), [2, 2]), ((1, 2), [1, 0]), ((2, 1), [0, 1]), ((1, 1), [2]), ((2, 0), [1, 2, 1, 2]), ((1, 0), [2]), ((0, 2), [0, 0, 0, 1])] 

Toute approche est préférable à un passage au-dessus de la liste de données pour chaque élément des combinaisons.

Pour travailler pour tuples de longueur arbitraire, nous avons juste besoin de créer les tuples en fonction de la longueur:

from collections import defaultdict 

n = 2 

next_ele_dict = defaultdict(list) 

def chunks(iterable, n): 
    for i in range(len(iterable)-n): 
     yield tuple(iterable[i:i+n]) 

data_iter = iter(Data[n:]) 
for tup in chunks(Data, n): 
     next_ele_dict[tup].append(next(data_iter)) 

def next_ele(): 
    for comb in set(Combinations): 
     if comb in next_ele_dict: 
      yield comb, next_ele_dict[comb] 


print(list(next_ele())) 

Vous pouvez l'appliquer à une implémentation particulière que vous préférez, la logique sera le même jusqu'à faire la Tuples va.

+0

Celui-ci ne fonctionne que si vous voulez comparer des couples de nombres –

+0

@RiccardoPetraglia * Si vous envisagez seulement des paires non-chevauchantes, (0,2) *, il peut facilement être adapté pour l'autre cas mais puisque l'OP ne compte que trois cas de '(0, 2)' arrive alors ils ne doivent pas être] –

+0

Oui, mais ce qu'il a écrit fonctionne aussi si vous décidez de comparer "triples" de nombres –

0
sum([all(x) for x in (Data[i:i+len(CurrentTuple)] == CurrentTuple for i in xrange 
(len(Data)-len(CurrentTuple)+1))]) 

Qu'est-ce que vous avez fait revenir un générateur qui produit la liste suivante:

[array([False, True], dtype=bool), 
array([ True, False], dtype=bool), 
array([False, True], dtype=bool), 
... 
array([False, False], dtype=bool), 
array([False, False], dtype=bool), 
array([False, False], dtype=bool), 
array([False, True], dtype=bool)] 

un du tableau que vous avez dans cette liste correspondent à la CurrentTuple seulement si le bool dans le tableau sont True. Le all renverra True seulement si tous les éléments de la liste sont True de sorte que la liste générée par le [all(x) for x in ...] contiendra True seulement si le jumeau des nombres correspond au CurrentTuple. Un True est considéré comme 1 lorsque vous utilisez sum. J'espère que c'est clair.

Si vous voulez comparer uniquement les paires qui ne se chevauchent:

[2,2, 
0,2, 
...] 

et de garder l'algorithme le plus général possible, vous pouvez utiliser les éléments suivants:

sum([all(x) for x in (Data[i:i+len(CurrentTuple)] == CurrentTuple for i in xrange 
(0,len(Data)-len(CurrentTuple)+1,len(CurrentTuple)))]) 

Malgré beaucoup plus cryptique, ce le code est beaucoup plus rapide que toute alternative que l'utilisation de append (regardez [Comparing list comprehensions and explicit loops (3 array generators faster than 1 for loop) pour comprendre pourquoi).