具有多个列表和if else条件的Python列表理解

时间:2016-11-07 08:11:32

标签: python list conditional list-comprehension

我想循环两个同样长的集合,并确定每个集合中的元素是否也在数组中。

这是我已经解决的Hackerrank问题。但是,我正在使用Hackerrank来进一步理解Python。我一直在学习列表理解,虽然我确实相信我试图将它用作被认为是糟糕的生产代码,但我仍然希望根据自己的知识探索语言语法的可能性。

这是设置它的代码:

n, m = map(int, input().split())
arr = list(map(int, input().split()))
A = set(map(int, input().split()))
B = set(map(int, input().split()))

任务是为A和arr中的每个元素输出一个值为+1的整数,并为B和arr中的每个元素输出-1。

示例输入:

3 2
1 5 3
3 1
5 7

示例输出:

1

这实现了所需的结果:

print(sum([1 for a in A if a in arr]) + sum([-1 for b in B if b in arr]))

然而,这更接近我想要实现的目标:

sum([1 if a in arr else -1 if b in arr for a, b in zip(A, B)])

编辑(实际上更接近):

print(sum(1 if a in arr -1 if b in arr for a, b in zip(A, B)))

正如你所看到的那样,两者都是单行的,所以它不是试图减少代码,而是要理解列表理解和pythonic代码的可能性。如果这不可能或甚至不好的做法我也很感兴趣。

这是Hackerrank链接: https://www.hackerrank.com/challenges/no-idea

5 个答案:

答案 0 :(得分:3)

如何将数组转换为设置和交叉点

arr

编辑:      此解决方案不适用于{{1}}

中的重复值

答案 1 :(得分:2)

首先,放弃列表理解;使用生成器表达式将值直接提供给sum()

sum(1 for a in A if a in arr)

如果A,请使用set.intersection() method提取常用值,然后获取结果的长度

len(A.intersection(arr)))

这比尝试为每个值测试arr要快。这个确实首先生成一个新的set()对象,但是之前你创建了一个列表,所以差别不大。

此时更简单只是减去第二个长度:

len(A.intersection(arr)) - len(B.intersection(arr))

您可以通过循环arr并在arr中针对AB测试每个值来完全避免创建集合。这也是更快,因为集合成员资格测试是O(1)常数时间:

sum(1 if v in A else -1 if v in B else 0 for v in arr)

如果值a in arr不存在,则对A集中的每个值测试arr的方法都需要a的完整列表扫描;这使得针对列表的成员资格测试成为O(N)线性时间问题,并且对A 中的每个值都对B中的每个值执行此操作,因此您结束用O((A + B)* N)== O(KN)时间。针对集合测试arr中的每个值仅为O(N * 1)== O(N)时间。

此外,如果arr 中的值不是唯一的,您的方法实际上会导致错误的答案;你只计算一次的快乐或不快乐的数字,而问题要求每次出现时都要对它们进行计数。

答案 2 :(得分:1)

你的解决方案很棒但是这里有一个问题。您为两组数字使用set数据结构,为数组使用list数据结构。当在列表顶部应用in运算符时,您正在进行O(n)搜索,而在集合中,相同的操作是O(logn)(在python平均情况下是O(1)!)。所以你的总时间复杂度是O(2 * m * n)= O(m * n)。您可以以相反的方式搜索,例如:

For each element in array, if element in A then +1, if element in B then -1.

这个的总复杂度是O(n * 2 * logm)= O(n * logm)

有关python时间复杂性的更多信息here

答案 3 :(得分:0)

这是我提交的答案,正如我首先想到的那样使用列表理解。这只是必要的,因为数组可能具有相同元素的倍数,因此计数需要反映这一点。

n, m = map(int, input().split())
arr = list(input().split())
A, B = set(input().split()), set(input().split())
print(sum([(e in A) - (e in B) for e in arr]))

答案 4 :(得分:0)

解决问题的最有效方法可能是将AB的项目放入字典(作为键),值为1或{{1取决于他们来自哪个集合。这将允许您浏览列表-1并轻松获取要添加到总和的值:

arr

结果的计算与在生成器表达式(ab_dict = {a: 1 for a in A} ab_dict.update((b, -1) for b in B) result = sum(ab_dict.get(x, 0) for x in arr) )中使用几个条件运算符具有相同的计算复杂度,但是应该通过某个常数因子更快,因为对于每个项目,只有一个dict查找而不是两套会员资格考试。