如何检查列表中的元素是否为相同类型,如果可能的话,而不必逐个检查每个元素?
例如,我想要一个函数来检查这个列表的每个元素是否为整数(显然是错误的):
x = [1, 2.5, 'a']
def checkIntegers(x):
# return True if all elements are integers, False otherwise
如何检查列表中的元素是否为相同类型,如果可能的话,而不必逐个检查每个元素?
例如,我想要一个函数来检查这个列表的每个元素是否为整数(显然是错误的):
x = [1, 2.5, 'a']
def checkIntegers(x):
# return True if all elements are integers, False otherwise
all
和 isinstance
:all(isinstance(x, int) for x in lst)
如果需要,您甚至可以使用 isinstance
检查多个类型:
all(isinstance(x, (int, long)) for x in lst)
class MyInt(int):
pass
print(isinstance(MyInt('3'),int)) #True
如果您需要限制自己仅使用整数,您可以使用all(type(x) is int for x in lst)
。但这是一种非常罕见的情况。
您可以编写一个有趣的函数,如果所有其他元素都是相同类型,则该函数将返回序列中第一个元素的类型:
def homogeneous_type(seq):
iseq = iter(seq)
first_type = type(next(iseq))
return first_type if all( (type(x) is first_type) for x in iseq ) else False
import inspect
def common_bases(seq):
iseq = iter(seq)
bases = set(inspect.getmro(type(next(iseq))))
for item in iseq:
bases = bases.intersection(inspect.getmro(type(item)))
if not bases:
break
return bases
homogeneous_type()
(我猜这就是函数的名称)对于空迭代器会出错。此外,结果取决于可迭代对象中项目的顺序(我猜这就是你所说的“迭代器”),这与我对此名称的函数所期望的不同。(例如,[0,False]
和[False,0]
。) - Sven Marnach[0,False]
或[False,0]
列表,我可以通过执行all(type(x) is first_type for x in iseq)
来修复它,但我认为如果函数也检查子类,则该函数将更有用。 - mgilsoniter(...)
或生成器)的可迭代对象,而不是不能被消耗的可迭代对象(list
,tuple
,...)?(感谢您对此进行了批判性的思考。希望这会带来更好的答案 :)) - mgilsonall()
还有一个优点,就是当它遇到生成器表达式中的 False
值时,它会短路并停止。 - dansalmox
不应该是列表对象吗? - Stevoisiakall
对于空的可迭代对象返回True
,这就是为什么homogeneous_type
适用于长度为1的序列。聪明! - Nathaniel Jonesany()
函数,无需遍历整个列表。只要找到不是 int
或 long
类型的对象就可以立即停止:>>> not any(not isinstance(y,(int,long)) for y in [1,2,3])
True
>>> not any(not isinstance(y,(int,long)) for y in [1,'a',2,3])
False
all
也会进行短路处理,因此这种方法与@mgilson的解决方案实际上没有什么区别。它更多的是一个逻辑练习... - mataany(not isinstance(e,type(seq[0])) for e in seq[1:])
。 - martineauseq
。否则,您需要使用iter
和next
--这样可以节省复制的开销,但对于列表来说,这通常是非常便宜的。 - mgilson%timeit all(isinstance(x, basestring) for x in list_w_int_or_str)
actually takes less time than %timeit not any(not isinstance(x, basestring) for x in list_w_int_or_str)
- Mark Mikofski结合之前给出的一些答案,使用map()、type()和set()的组合提供了一个我认为相当易读的答案。假设不检查类型多态性的限制是可以接受的。这也不是最高效的答案,但它允许轻松地检查所有元素是否属于同一类型。
# To check whether all elements in a list are integers
set(map(type, [1,2,3])) == {int}
# To check whether all elements are of the same type
len(set(map(type, [1,2,3]))) == 1
检查列表是否由同类元素组成的最简单方法是使用itertools模块的groupby函数:
from itertools import groupby
len(list(groupby(yourlist,lambda i:type(i)))) == 1
如果len与1不同,那么它意味着在列表中找到了不同种类的类型。
这个问题是需要遍历整个序列。
如果你想要一个懒惰版本,可以编写一个函数:
def same(iterable):
iterable = iter(iterable)
try:
first = type(next(iterable))
return all(isinstance(i,first) for i in iterable)
except StopIteration:
return True
这个函数会存储第一个元素的类型,并且一旦在列表中的元素中发现不同类型,就停止执行。
这两种方法都对类型非常敏感,所以它们将把int和float视为不同的类型,但这应该是您能够接近您请求的结果的最佳选择。
编辑:
根据mgilson的建议,用all函数的调用替换了for循环。
如果是空迭代器,则返回True,以保持与内置的all函数的行为一致。
a = iter(obj); t = type(next(a)); all(isinstance(x, t) for x in a)
。对于一个列表来说,甚至更容易,这就是问题所在 -- t = type(lst[0]); return all(instance(x,t) for x in lst[1:])
。不错。 - mgilsontype
,而不是 lambda i: type(i)
。 - Sven Marnach>>> def checkInt(l):
return all(isinstance(i, (int, long)) for i in l)
>>> checkInt([1,2,3])
True
>>> checkInt(['a',1,2,3])
False
>>> checkInt([1,2,3,238762384762364892364])
True
isinstance()
比type()
更好。 - Ashwini Chaudharyisinstance()
还是 type()
? - linelloisinstance(i, (int, long))
很简短。它不是关于速度的问题,而是 type()
会对 int 的子类失效。 - Ashwini Chaudharyitertools
文档中"Itertools recipes"部分的all_equal
函数:from itertools import groupby
def all_equal(iterable):
"Returns True if all the elements are equal to each other"
g = groupby(iterable)
return next(g, True) and not next(g, False)
more_itertools
中:pip install more-itertools
扩展工具提供与基础工具集相同的高性能。通过一次处理一个元素而不是一次将整个可迭代对象带入内存,保持了卓越的内存性能。通过以函数式样式将工具链接在一起来消除临时变量,代码量保持较小。通过优先选择“矢量化”的构建块而不是使用for循环和生成器来避免解释器开销,保留了高速度。from more_itertools import all_equal
all_equal(map(type, iterable))
isinstance
和已知类型 int
(如原始问题中所述)。all_equal(map(lambda x: isinstance(x, int), iterable))
range(0)
)。all_equal(map(type, range(0))) # True
all_equal(map(type, range(1))) # True
all_equal(map(type, range(2))) # True
all_equal(map(lambda x: isinstance(x, int), range(0))) # True
all_equal(map(lambda x: isinstance(x, int), range(1))) # True
all_equal(map(lambda x: isinstance(x, int), range(2))) # True
如果您想要排除子类,也可以使用 type()
。请参阅isinstance()
和 type()
的区别:
>>> not any(not type(y) is int for y in [1, 2, 3])
True
>>> not any(not type(y) == int for y in [1, 'a', 2.3])
False
def checkIntegers(x):
# return True if all elements are integers, False otherwise
return all(isinstance(i, type(x[0])) for i in x[1:])
x = [1, 2.5, 'a']
checkIntegers(x)
False
def check_item_dtype_in_list(item_range):
if all(map(lambda x: str(x).isdigit(), item_range)):
item_range = list(map(int, item_range))
print('all are integer')
print(item_range)
return
elif all(isinstance(item, str) for item in item_range):
print('all are string')
print(item_range)
return
elif any(map(lambda x: str(x), item_range)):
print('mixed dtype')
print(item_range)
return
check_item_dtype_in_list(['2', 2, 3])
check_item_dtype_in_list(["2", 2, 'Two'])
check_item_dtype_in_list(['Two', 'Two', 'Two'])
check_item_dtype_in_list([2, 2., 'Two'])
all are integer
[2, 2, 3]
mixed dtype
['2', 2, 'Two']
all are string
['Two', 'Two', 'Two']
mixed dtype
[2, 2.0, 'Two']
def c(x):
for i in x:
if isinstance(i,str):
return False
if isinstance(i,float):
return False
return True
all
是正确的方法... - linello