2016-02-22 11 views
5

Ho un elenco di tuple che è stato creato con la funzione zip. zip riunisce quattro elenchi: narrative, subject, activity e filer, ognuno dei quali è solo un elenco di 0 e 1. Diciamo che quei quattro liste simile a questa:Filtra una tupla con un'altra tupla in Python

narrative = [0, 0, 0, 0] 
subject = [1, 1, 0, 1] 
activity = [0, 0, 0, 1] 
filer = [0, 1, 1, 0] 

Ora, io sono zip ing insieme per ottenere un elenco di valori booleani che indica se qualcuno di loro sono True.

ny_nexus = [True if sum(x) > 0 else False for x in zip(narrative, subject, activity, filer)]

Il problema che sto avendo ora, sta ottenendo un secondo elenco di tuple per i quali i nomi delle variabili viene restituito se avesse un 1 durante l'iterazione. Immagino che sarebbe simile a questa:

variables = ("narrative", "subject", "activity", "filer") 
reason = [", ".join([some code to filter a tuple]) for x in zip(narrative, subject, activity, filer)] 

io proprio non riesco a capire come mi piacerebbe andare su questo. La mia uscita desiderata sarebbe simile a questa:

reason 
# ["subject", "subject, filer", "filer", "subject, activity"] 

Sono un po 'nuovo a Python, quindi mi scuso se la soluzione è semplice.

+1

A proposito, puoi dire 'ny_nexus = [somma (x)> 0 per x in zip ...]' – zondo

+0

Apprezzo sempre il codice più conciso. Grazie – brittenb

+1

Ancora meglio, usa la funzione built-in 'any();)' any ([0, 0, 0]) == False', 'any ([0, 1, 0]) == True'. Quindi, 'ny_nexus = [any (x) per x in zip ...]' – AkiRoss

risposta

3

tuple Conservare in un dizionario per una soluzione più pulita:

tups = {'narrative': narrative, 
     'subject': subject, 
     'activity': activity, 
     'filer': filer} 

La soluzione:

reason = [', '.join(k for k, b in zip(tups, x) if b) for x in zip(*tups.values())] 

Può anche essere scritto utilizzando itertools.compress :

from itertools import compress 
reason = [', '.join(compress(tups, x)) for x in zip(*tups.values())] 

soluzioni sopra non mantengono l'ordine di tuple, ad esempiopossono tornare qualcosa come

['subject', 'filer, subject', 'filer', 'activity, subject'] 

Se è necessario l'ordine da conservare, utilizzare collections.OrderedDict come illustrato di seguito:

from collections import OrderedDict 

tups = OrderedDict([ 
    ('narrative', narrative), 
    ('subject', subject), 
    ('activity', activity), 
    ('filer', filer) 
]) 

# The result is ['subject', 'subject, filer', 'filer', 'subject, activity'] 

EDIT: La soluzione che non comporta dizionari:

from itertools import compress 
reason = [', '.join(compress(variables, x)) 
      for x in zip(narrative, subject, activity, filer)] 

Considerare l'utilizzo dei dizionari se loLa chiamatanon si adatta più a una riga.

+0

Finora questa è l'unica soluzione che funziona. Tuttavia, è quello che ho capito di meno. Puoi spiegare cosa fa 'compress', insieme a quello che il ruolo '*' gioca in 'zip (* tups.values ​​())' per favore? – brittenb

+0

@vaultah: Non vedo come un dizionario o OrderedDict renda questo più pulito. Hai già ottenuto 'compress()', perché non dare da solo la tupla 'variables' di OP? –

+0

@brittenb: se guardi la documentazione di 'compress()', vedrai che fa esattamente quello che stai cercando. Seleziona elementi di una sequenza in base al fatto che gli elementi corrispondenti di un'altra sequenza siano veri. –

0

si può semplicemente utilizzare l'aspetto di filtraggio della sintassi di comprensione per ottenere tuo vaiable nome inglese solo se il rispettivo flag è vero:

variables = ("narrative", "subject", "activity", "filer") 
[tuple (name for flag, name in zip(x, variables) if x) for x in zip(narrative, subject, activity, filer)] 

Detto questo, c'è qualcosa di sospetto circa il suo approccio - si' Probabilmente sarà (molto) migliore con un approccio orientato agli oggetti, invece di cercare di coordinare manualmente sequenze indipendenti di variabili per ciascuno dei tuoi soggetti.

+0

Questo approccio ha senso per me, ma dato che 'x' valuterà sempre come Truthy, restituisce tutti i valori in' variables'. Puoi approfondire il tuo approccio orientato agli oggetti? Non sono sposato con il modo in cui lo sto facendo e sono sempre disposto a provare nuovi metodi. – brittenb

0
narrative = [0, 0, 0, 0] 
    subject = [1, 1, 0, 1] 
    activity = [0, 0, 0, 1] 
    filer = [0, 1, 1, 0] 
    variables = ("narrative", "subject", "activity", "filer") 
    ny_nexus = [True if sum(x) > 0 else False for x in zip(narrative, subject, activity, filer)] 
    output = [] 
    [[output.append(variables[j]) if t==1 else None for j,t in enumerate(x)] for x in zip(narrative, subject, activity, filer)] 
    print ny_nexus 
    print output 

Naturalmente si può solo effettuare le seguenti operazioni senza usare list comprehensions:

narrative = [0, 0, 0, 0] 
    subject = [1, 1, 0, 1] 
    activity = [0, 0, 0, 1] 
    filer = [0, 1, 1, 0] 
    variables = ("narrative", "subject", "activity", "filer") 
    ny_nexus = [True if sum(x) > 0 else False for x in zip(narrative, subject, activity, filer)] 
    output = [] 
    for x in zip(narrative, subject, activity, filer): 
     for j,t in enumerate(x): 
      output.append(variables[j]) 
    print ny_nexus 
    print output 
+0

Questo approccio ha anche senso per me, ma restituisce "Nessuno" per tutti i valori. Qualche idea del perché? – brittenb

+0

I risultati di ny_nexus nel codice precedente sono in realtà inutili. I risultati utili sono solo in uscita. In effetti, puoi cambiare il nome di ny_nexus in tmp o qualcosa e ignorarlo. Il codice sopra sarebbe richiesto in aggiunta alla seguente dichiarazione: ny_nexus = [Vero se somma (x)> 0 altro Falso per x in zip (narrativa, soggetto, attività, filer)] – Sid

+0

Risposta aggiornata per riflettere – Sid

1

Utilizzando zip(narrative, subject, activity, filer) traspone fondamentalmente la matrice (l'elenco delle liste di uguale lunghezza compongono la matrice). Quindi si enumera attraverso questi per trovare la posizione n di dove il flag è true e indicizzare la variabile appropriata.

narrative = [0, 0, 0, 0] 
subject = [1, 1, 0, 1] 
activity = [0, 0, 0, 1] 
filer = [0, 1, 1, 0] 
variables = ("narrative", "subject", "activity", "filer") 
# ======================================================== 

new_list = [[variables[n] for n, flag in enumerate(indicators) if flag] 
      for indicators in zip(narrative, subject, activity, filer)] 
>>> new_list 
[['subject'], ['subject', 'filer'], ['filer'], ['subject', 'activity']] 

Per vedere la trasposizione:

>>> [i for i in zip(narrative, subject, activity, filer)]