如何检查列表'a'中的元素是否符合列表'b'中的条件?

9
我有一个数字列表:
a = [3, 6, 20, 24, 36, 92, 130]

以下是条件列表:

b = ["2", "5", "20", "range(50,100)", ">120"]

我希望检查'a'中的数字是否符合'b'中的任一条件,如果符合,则将这些数字放入列表'c'中。
在上述情况下:
c = [20, 92, 130]

我创建了这段代码,看起来能够实现我想要的功能:
c = []
for x in a:
    for y in b:
        if "range" in y:
            rangelist = list(eval(y))
            if x in rangelist:
                c.append(x)
        elif ">" in y or "<" in y:
            if eval(str(x) + y):
                c.append(x)
        else:
            if x == eval(y):
                c.append(x)

然而,我的列表'a'可能非常大。
有没有更简单、更快速的方法来获取我想要的东西?


1
为什么你在条件语句中保存字符串而不是整数,这样做会更容易。 - user1767754
1
你能否将 b 更改为有效的条件,例如 =20在范围(50,100)内 - Mureinik
11
把函数放进你的 b 列表里似乎更加简洁,而不是进行一堆拙劣的字符串操作和 eval - user2357112
2
类似于 lambda x: x > 120lambda x: 50 <= x < 100 这样的东西。 - user2357112
2
这是一项有趣的Haskell练习,因为它涉及到定义一个a -> [(a -> b)] -> [b]类型的反向映射(这可能是Haskell stdlib中的内容,但我找不到),可在此处查看我的解决方案 - Adam Smith
显示剩余4条评论
4个回答

13

借鉴@user2357112的建议,您可以创建一个包含所有条件的函数列表,然后将每个数字传递给每个函数以确定该数字是否符合任何条件。

In [1]: a = [3, 6, 20, 24, 36, 92, 130]

In [2]: conditions = [lambda x:x==2, lambda x:x==5, lambda x:x==20, lambda x: x in range(50, 100), lambda x: x > 120]  # List of lambda functions

In [3]: output = list()

In [4]: for number in a:
   ...:     if any(func(number) for func in conditions): # Check if the number satisfies any of the given conditions by passing the number as an argument to each function
   ...:         output.append(number)         

In [5]: output
Out[5]: [20, 92, 130]

2
我绝对更喜欢这个解决方案,喜欢Lambda的创造性使用方式。 - user1767754
很好的解决方案,但我如何将列表'b'更改为lambda条件? - Reman
@Reman 我已经将列表“b”中的所有条件转换为lambda函数,并将它们存储在列表“conditions”中。 - GaneshTata
@GaneshTata,是的,我看到了,但是我没有可能在我的列表“b”中有lambda函数。我有一个像问题中的列表'b'。我必须调整它们,包括lambda函数...使用列表推导式吗?类似这样conditions = ["x:x==" + a if a.isdigit() elif "x: x in " + a if "range" in a else "a: a " + a for a in b] - Reman
1
发现它:["x:x==" + a if a.isdigit() else "x: x in " + a if "range" in a else "a: a " + a for a in b] - Reman

4
假设您可以根据上面评论中讨论的方法,更改b以保持有效条件(与a中的元素连接起来),则:
b = ["==2", "==5", "==20", "in range(50,100)", ">120"]

你可以将a中的每个元素与这些条件连接起来,并使用eval检查它是否评估为TrueFalse。当然,这可以在列表理解中完成:
result = [i for i in a if any(eval(str(i) + x) for x in b)]

谢谢,如果你取 a = [3, 6, 20, 24, 36, 92, 130, 180, 182, 190]b = ['==2', 'in range(150,200)', '<120', '180'],那么输出结果是错误的。 - Reman
180 是一个数字,而不是一个条件。程序将两个字符串连接起来,Python 将所有具有值的内容解释为 True。您可以使用 print(not(3180)) 进行检查。 - Mr. T
如果我使用上述列表... '130' 将会出现在结果中。 - Reman

2

如果你想要简单、Pythonic且易于理解的内容,忘掉上面那些。

a = [3, 6, 20, 24, 36, 92, 130]
[i for i in a if i==2 or i==5 or i==20 or i>120 or 50<=i<=100 ]

2

根据之前的答案,我认为还有两种方法。

#1
numbers = [3, 6, 20, 24, 36, 92, 130]
conditions = [
    lambda n: n == 2,
    lambda n: n == 5,
    lambda n: n == 20,
    lambda n: n in range(50, 100),
    lambda n: n > 120,
]
result = [num for num in numbers for condition in conditions if condition(num)]

#2
condition = lambda n: n in {2, 5, 20} or 50 <= n <= 100 or n > 120
result = list(filter(condition, numbers))

对于一个非常大的列表,你应该选择示例#2,因为它更加节省内存,并且时间复杂度是线性的,而不是像示例#1一样是二次方的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接