Check if all elements of a list are of the same type
Solution 1
Try using all
in conjunction with isinstance
:
all(isinstance(x, int) for x in lst)
You can even check for multiple types with isinstance
if that is desireable:
all(isinstance(x, (int, long)) for x in lst)
Not that this will pick up inherited classes as well. e.g.:
class MyInt(int):
pass
print(isinstance(MyInt('3'),int)) #True
If you need to restrict yourself to just integers, you could use all(type(x) is int for x in lst)
. But that is a VERY rare scenario.
A fun function you could write with this is one which would return the type of the first element in a sequence if all the other elements are the same type:
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
This will work for any arbitrary iterable, but it will consume "iterators" in the process.
Another fun function in the same vein which returns the set of common bases:
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
Solution 2
Using any()
, no need to traverse whole list. Just break as soon as object which is not int
or long
is found:
>>> 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
Solution 3
Combining some of the answers already given, using a combination of map(), type() and set() provides a imho rather readable answer. Assuming the limitation of not checking for type polymorphisms is ok. Also not the most computationally efficient answer, but it allows to easily check whether all elements are of the same type.
# 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
Solution 4
>>> 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
Solution 5
The simplest way to check if a list is composed of omogeneous elements can be with the groupby function of the itertools module:
from itertools import groupby
len(list(groupby(yourlist,lambda i:type(i)))) == 1
If th len is different from one it means that it found different kind of types in the list. This has the problem of running trough the entire sequence. If you want a lazy version you can write a function for that:
def same(iterable):
iterable = iter(iterable)
try:
first = type(next(iterable))
return all(isinstance(i,first) for i in iterable)
except StopIteration:
return True
This function store the type of the first element and stop as soon as it find a different type in one of the elements in the list.
Both of this methods are strongly sensitive to the type, so it will see as different int and float, but this should be as close as you can get to your request
EDIT:
replaced the for cycle with a call to all as suggested by mgilson
in case of void iterator it returns True to be consistent with the behavior of the bulitin all function
linello
Currently I'm scientific software developer with proficiency in C/C++ with their related technologies Boost, STL, Qt, Python, computer graphics, OpenGL, Mathematica, MatLab, Bash scripting, NI Labview, LATEX, CMake, CUDA.
Updated on May 31, 2021Comments
-
linello about 3 years
How can I check if the elements of a list are of the same type, without checking individually every element if possible?
For example, I would like to have a function to check that every element of this list is an integer (which is clearly false):
x = [1, 2.5, 'a'] def checkIntegers(x): # return True if all elements are integers, False otherwise
-
Ashwini Chaudhary over 11 years
isinstance()
should be preferred overtype()
. -
linello over 11 yearsWhich of the two is faster,
isinstance()
ortype()
? -
Ashwini Chaudhary over 11 years
isinstance(i,(int,long))
is short. it's not about speed, type() will fail for subclasses of int -
Inbar Rose over 11 years@mgilson yeah, i just noticed also that you beat me to the answer anyway. :)
-
mgilson over 11 yearsThe logic is much more clean with
all
, but I supposenot any(not condition ...)
works too. +1 for your efforts I suppose (and for demonstratingall
's counterpart, which is just as useful.) -
EnricoGiampieri over 11 yearsThe first request of the OP is not to check is all the elements were of a specific type, but to check if all the element were of the same type, indipendently from which one was the first. It is a solution to a slightly different problem.
-
Ashwini Chaudhary over 11 years@mgilson This occured to me when I saw your comment :), otherwise I was happy with
all()
based solution. -
mgilson over 11 years@EnricoGiampieri -- but you can still do a short circuiting version in 3 lines.
a=iter(obj);t=type(next(a));all(isinstance(x,t) for x in a)
. It's even easier for a list which is what the question is about --t = type(lst[0]); return all(instance(x,t) for x in lst[1:])
. Not too shabby. -
EnricoGiampieri over 11 yearsyes, you can shortcircuit it, but it will not handle void iterators and will raise an exception. It's just a matter of choice, in my case i prefere to handle it instead of raising
-
mata over 11 years
all
also short circuits, so there isn't really any difference between this and @mgilson's solution. It's more an exercise in logic... -
martineau over 11 yearsGenerically speaking, I think what you'd need to do is check if any element is not the same type as the first. i.e.
any(not isinstance(e,type(seq[0])) for e in seq[1:])
-
mgilson over 11 years@martineau -- Assuming that you can slice
seq
of course. Otherwise you need to useiter
andnext
-- Which saves you the overhead of making a copy, but that's typically pretty cheap for lists. -
Sven Marnach over 11 yearsNote that
homogeneous_type()
(I guess that's what the function is supposed to be called) errors out for empty iterators. Moreover, the result depends on the order of the items in the iterable (I guess this is what you mean by "iterator"), which is not what I would expect from a function of this name. (An example would be[0, False]
and[False, 0]
.) -
Sven Marnach over 11 yearsInstead of
lambda i: type(i)
, you can simply usetype
. -
mgilson over 11 years@SvenMarnach -- I suppose that's a reasonable point. I think that it's fine to error out on empty iterators (I actually considered that when I wrote the function) ... What should the result be in the case of an empty iterable? As far as passing a list of
[0, False]
or[False, 0]
, I could fix that by doingall( type(x) is first_type for x in iseq )
, but it seems to me that the function would be more useful if it checked out OK for subclasses as well. -
mgilson over 11 years@SvenMarnach -- Finally, Yes I did mean
iterable
. For semantics, what term would you use to describe iterables that can be consumed (iter(...)
or generators) vs iterables which cannot (list
,tuple
, ...)? (And thanks for looking at this critically. Hopefully it'll make for a better answer :) -
dansalmo about 11 years
all()
also has the advantage in that it will short circuit and stop as soon as it encounters aFalse
value from the generator expression. -
Mark Mikofski over 10 years
%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)
-
Stevoisiak over 6 yearsBased on the question's code example, shouldn't
x
be the list object? -
Nathaniel Jones over 5 yearsJust realized that
all
returnsTrue
for an empty iterable, which is whyhomogeneous_type
works for sequences of length 1. Clever!