【问题标题】:Filter a tuple with another tuple in Python在 Python 中用另一个元组过滤一个元组
【发布时间】:2016-02-22 16:42:38
【问题描述】:

我有一个使用zip 函数创建的元组列表。 zip 汇集了四个列表:narrativesubjectactivityfiler,每个列表都只是 0 和 1 的列表。假设这四个列表如下所示:

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

现在,我将 zip 将它们放在一起以获取布尔值列表,指示它们中是否有任何 True

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

我现在遇到的问题是获取第二个元组列表,如果它在迭代期间为 1,则返回变量的名称。我想它看起来像这样:

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

我只是不知道该怎么做。我想要的输出如下所示:

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

我对 Python 有点陌生,所以如果解决方案很简单,我深表歉意。

【问题讨论】:

  • 对了,你可以说ny_nexus = [sum(x) > 0 for x in zip...]
  • 总是欣赏更简洁的代码。谢谢
  • 更好的是,使用 any() 内置函数 ;) any([0, 0, 0]) == False, any([0, 1, 0]) == True。所以,ny_nexus = [any(x) for x in zip...]

标签: python list tuples


【解决方案1】:

将元组存储在字典中以获得更简洁的解决方案:

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

解决办法:

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

也可以用itertools.compress写:

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

上述解决方案不保留元组的顺序,例如他们可以返回类似的东西

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

如果您需要保留订单,请使用collections.OrderedDict,如下所示:

from collections import OrderedDict

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

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

编辑:不涉及字典的解决方案:

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

如果zip(...) 调用不再适合一行,请考虑使用字典。

【讨论】:

  • 到目前为止,这是唯一有效的解决方案。然而,这是我最了解的一个。你能解释一下compress 的作用,以及*zip(*tups.values()) 中的作用吗?
  • @vaultah:我看不出字典或 OrderedDict 是如何让这变得更干净的。你已经有了compress(),为什么不直接喂它OP的variables元组呢?
  • @brittenb:如果您查看compress() 的文档,您会发现它几乎完全符合您的要求。它根据另一个序列的对应元素是否为真来选择一个序列的元素。
  • @JohnY 是的,我刚刚提取了它的文档,它非常不言自明。基于此,这个问题的正确解决方案似乎是reason = [", ".join(compress(variables, x)) for x in zip(narrative, subject, activity, filer)]
  • @brittenb:完全正确。在这种情况下,不需要弄乱字典或星号运算符。 (这会很方便,official tutorial 会检查它,但您可以稍后再担心。)
【解决方案2】:

使用zip(narrative, subject, activity, filer) 基本上会转置矩阵(您的等长列表组成矩阵)。然后您通过这些枚举找到标志为真的位置n 并索引适当的变量。

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

要查看转置:

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

【讨论】:

    【解决方案3】:

    您可以只使用理解语法的过滤方面来获取 仅当相应标志为 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)]
    

    也就是说,您的方法有些可疑 - 您可能会(远远)更好地使用面向对象的方法,而不是尝试手动协调每个主题的独立变量序列。

    【讨论】:

    • 这种方法对我来说很有意义,但由于x 将始终评估为Truthy,它返回variables 中的所有值。你能详细说明你的面向对象方法吗?我不喜欢我目前的做法,我总是愿意尝试新的方法。
    【解决方案4】:
        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
    

    当然,您可以在不使用列表推导的情况下执行以下操作:

        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
    

    【讨论】:

    • 这种方法对我来说也很有意义,但它会为所有值返回None。知道为什么吗?
    • 上面代码中ny_nexus的结果其实是没用的。有用的结果只在输出中。实际上,您可以将 ny_nexus 的名称更改为 tmp 或其他名称,然后忽略它。除了以下语句之外,还需要上述代码:ny_nexus = [True if sum(x) > 0 else False for x in zip(narrative, subject, activity, filer)]
    • 更新答案以反映
    猜你喜欢
    • 2013-02-26
    • 1970-01-01
    • 2016-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-07
    • 2019-01-18
    相关资源
    最近更新 更多