Check if all elements of a list are of the same type

95,700

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

Share:
95,700
linello
Author by

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, 2021

Comments

  • linello
    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
    Ashwini Chaudhary over 11 years
    isinstance() should be preferred over type().
  • linello
    linello over 11 years
    Which of the two is faster, isinstance() or type()?
  • Ashwini Chaudhary
    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
    Inbar Rose over 11 years
    @mgilson yeah, i just noticed also that you beat me to the answer anyway. :)
  • mgilson
    mgilson over 11 years
    The logic is much more clean with all, but I suppose not any(not condition ...) works too. +1 for your efforts I suppose (and for demonstrating all's counterpart, which is just as useful.)
  • EnricoGiampieri
    EnricoGiampieri over 11 years
    The 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
    Ashwini Chaudhary over 11 years
    @mgilson This occured to me when I saw your comment :), otherwise I was happy with all() based solution.
  • mgilson
    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
    EnricoGiampieri over 11 years
    yes, 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
    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
    martineau over 11 years
    Generically 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
    mgilson over 11 years
    @martineau -- Assuming that you can slice seq of course. Otherwise you need to use iter and next -- Which saves you the overhead of making a copy, but that's typically pretty cheap for lists.
  • Sven Marnach
    Sven Marnach over 11 years
    Note 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
    Sven Marnach over 11 years
    Instead of lambda i: type(i), you can simply use type.
  • mgilson
    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 doing all( 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
    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
    dansalmo about 11 years
    all() also has the advantage in that it will short circuit and stop as soon as it encounters a False value from the generator expression.
  • Mark Mikofski
    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
    Stevoisiak over 6 years
    Based on the question's code example, shouldn't x be the list object?
  • Nathaniel Jones
    Nathaniel Jones over 5 years
    Just realized that all returns True for an empty iterable, which is why homogeneous_type works for sequences of length 1. Clever!