简体   繁体   中英

Filter a tuple with another tuple in Python

I have a list of tuples that is created with the zip function. zip is bringing together four lists: narrative , subject , activity , and filer , each of which is just a list of 0s and 1s. Let's say those four lists look like this:

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

Now, I'm zip ing them together to get a list of boolean values indicating if any of them are True .

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

The problem I'm having now, is getting a second list of tuples for which the names of the variables is returned if it had a 1 during the iteration. I imagine it would look something like this:

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

I just can't figure out how I'd go about this. My desired output would look like this:

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

I'm somewhat new to Python, so I apologize if the solution is easy.

Store tuples in a dictionary for a cleaner solution:

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

The solution:

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

It can also be written using itertools.compress :

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

Solutions above do not preserve the order of tuples, eg they can return something like

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

If you need the order to be preserved, use collections.OrderedDict as shown below:

from collections import OrderedDict

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

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

EDIT: The solution that doesn't involve dictionaries:

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

Consider using dictionaries if the zip(...) call no longer fits on one line.

Using zip(narrative, subject, activity, filer) basically transposes the matrix (your list of lists of equal length make up the matrix). You then enumerate through these to find the location n of where the flag is true and index the appropriate variable.

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']]

To see the transpose:

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

You can just use the filtering aspect of the comprehension syntax to get your vaiable English name only if the respective flag is True:

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

That said, there is something fishy about your approach - you'd probbly be (far) better of with an object oriented approach there, instead of trying to manually coordinate independent sequences of variables for each of your subjects.

    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

Of course you could just do the following without using 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM