检查两个Python列表是否按类型相等

11

我想检查两个列表在每个索引处的项是否具有相同的类型。例如,如果我有

y = [3, "a"]
x = [5, "b"] 
z = ["b", 5]

对于xy,检查结果应为True

对于yz,检查结果应为False,因为相同位置的元素类型不相等。

6个回答

18

只需将元素映射到它们相应的类型并进行比较:

>>> x = [5, "b"] 
>>> y = [3, "a"]
>>> z = ["b", 5]
>>> map(type, x) == map(type, y)
True
>>> map(type, x) == map(type, z)
False

对于Python 3,您还需要将map生成器转换为适当的列表,可以使用list函数或使用列表推导式

>>> list(map(type, x)) == list(map(type, y))
True
>>> [type(i) for i in x] == [type(i) for i in z]
False

我进行了一些时间分析,将上述解决方案与@timgeb的解决方案进行了比较,使用allizip以及在不同位置具有第一个非匹配类型的输入。正如预期的那样,对于每个输入,map解决方案所需的时间几乎完全相同,而all+izip解决方案可能非常快或需要三倍的时间,这取决于第一个差异的位置。

In [52]: x = [1] * 1000 + ["s"] * 1000
In [53]: y = [2] * 1000 + ["t"] * 1000 # same types as x
In [54]: z = ["u"] * 1000 + [3] * 1000 # difference at first element
In [55]: u = [4] * 2000                # difference after first half
In [56]: %timeit map(type, x) == map(type, y)
10000 loops, best of 3: 129 µs per loop
In [58]: %timeit all(type(i) == type(j) for i, j in izip(x, y))
1000 loops, best of 3: 342 µs per loop
In [59]: %timeit all(type(i) == type(j) for i, j in izip(x, z))
1000000 loops, best of 3: 748 ns per loop
In [60]: %timeit all(type(i) == type(j) for i, j in izip(x, u))
10000 loops, best of 3: 174 µs per loop

1
使用 "all(...)" 会使它更快,类似于 @timgeb 的做法。 - fransua
@fransua 也许是这样,但你必须使用 itertools.izip_longest 才能使其适用于长度不相等的列表,而且在我看来,这只会使代码更加复杂(除非列表特别长)。 - tobias_k

18

使用 all 进行惰性求值:

>>> from itertools import izip
>>> all(type(a) == type(b) for a,b in izip(x,y))
True

在Python 3中,请使用常规的zip函数,它已经返回一个生成器。

如果列表的长度可能不同,请在开始时检查长度。检查长度是非常快速的O(1)操作:

>>> len(x) == len(y) and all(type(a) == type(b) for a,b in izip(x,y))
True
>>> x = [5,"b",'foo']
>>> len(x) == len(y) and all(type(a) == type(b) for a,b in izip(x,y))
False
< p >如果长度不同,and将进行短路评估,这意味着all甚至不会被调用。


2
不错,但是不能处理长度不同的列表... 或许可以使用 itertools.izip_longest 代替? - tobias_k
1
它仍然可以工作,所以我看不出需要使用itertools。 对我来说,元组列表并不比生成器更糟糕。 - zondo
1
@tobias_k 我考虑过使用 izip_longest,但你会用什么作为填充值,以避免它成为列表元素?我认为在这里事先检查长度更好。 - timgeb
2
@zondo 不是所有的元组都需要。对于 x = [1, 2, 3]y = ['foo', 2, 3],只需要第一个元组。 - timgeb
1
@zondo 这不是一个比赛。你问我为什么使用izip,我解释了一下。 :) - timgeb
显示剩余7条评论

3

使用lambda的另一种选择:

>>> x = [5, "b"]
>>> y = [3, "a"]
>>> z = ["b", 5]
>>> g = lambda t: [type(i) for i in t]
>>> g(x) == g(y)
True
>>> g(x) == g(z)
False

2
当你使用生成器表达式时,它非常简单:
are_equal = all(type(i) == type(j) for i, j in zip(x, y))

在这个例子中,xy是您要检查的列表。 如果您想要添加内容,请使用以下代码:
lists = (x, y)
are_equal = all(len(set(type(j) for j in i)) == 1 for i in zip(*lists))

以这种方式,您只需更改lists,它仍然可以正常工作。 它的工作原理是利用了set会删除所有重复项的事实。 对于每个由zip()返回的元组,它创建了每个项目类型的集合,并检查它们是否相同,方法是查看集合的长度是否为1。

你的第二部分没有根据位置比较类型。特别是,它显示 xztrue - tobias_k
@tobias_k:糟糕,我刚才漏掉了几个字符。现在已经修复了。 - zondo
我不明白你的意思。set(type(j) for j in i))会给出当前zip元组中每个元素类型的集合。如果该集合的长度不为1,则其中一个元素与其他元素的类型不同。我已经测试过它,看起来它是有效的。我是否漏掉了什么? - zondo
你是对的,抱歉,我混淆了这行代码的作用,并且在测试时似乎犯了一个错误。对于比较任意数量列表类型的解决方案加1,但对于两个列表来说,我认为这个解决方案非常难以理解。 - tobias_k
我在我的回答中尝试了一些解释。有什么可能不清楚的吗? - zondo

0
def equalTypes(list1, list2):
    if len(list1) != len(list2):
        return False
    for index, item in enumerate(list1):
        if type(item) != type(list2[index]):
            return False
    return True

我只是遍历列表(首先检查它们是否具有相同的长度),然后当某些类型不匹配时,我返回False。最后(没有不匹配),我返回True。


0

你可以使用 itertoolsoperator.eq 来保持惰性求值,这样可以在不存储列表副本的情况下获得相当不错的平均时间:

In [12]: from itertools import imap, starmap, izip

In [13]: %timeit map(type, x) == map(type, y)
10000 loops, best of 3: 182 µs per loop

In [14]: %timeit all(type(i) == type(j) for i, j in izip(x, u))
1000 loops, best of 3: 239 µs per loop

In [15]: timeit all(type(i) == type(j) for i, j in izip(x, z))
1000000 loops, best of 3: 1.02 µs per loop

In [16]:  %timeit all(type(i) == type(j) for i, j in izip(x, u))
1000 loops, best of 3: 234 µs per loop

In [17]: timeit all(starmap(eq, izip(imap(type, x), imap(type, y))))
1000 loops, best of 3: 238 µs per loop

In [18]: timeit all(starmap(eq, izip(imap(type, x), imap(type, u))))
10000 loops, best of 3: 120 µs per loop

In [19]: timeit all(starmap(eq, izip(imap(type, x), imap(type, z))))
1000000 loops, best of 3: 901 ns per loop

如果列表长度不同,首先检查长度可能是最简单和最快的方法,但如果你要将其纳入逻辑中,可以使用itertools.izip_longest并将object作为fillvalue
all(starmap(eq, izip_longest(imap(type, x), imap(type, y), fillvalue=object()))

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