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

前端 未结 9 1686
盖世英雄少女心
盖世英雄少女心 2020-11-28 05:08

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

相关标签:
9条回答
  • 2020-11-28 05:34

    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
    
    0 讨论(0)
  • 2020-11-28 05:39

    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
    

    0 讨论(0)
  • 2020-11-28 05:43
        def c(x):
             for i in x:
                 if isinstance(i,str):
                       return False
                 if isinstance(i,float):
                       return False
    
              return True
    
    0 讨论(0)
  • 2020-11-28 05:47
    >>> 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
    
    0 讨论(0)
  • 2020-11-28 05:50

    You can also use type() if you want to exclude subclasses. See the difference between isinstance() and 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
    

    Although you may not want to, because this will be more fragile. If y changes its type to a subclass of int, this code will break, whereas isinstance() will still work.

    It's OK to use is because there is only one <type 'int'> in memory, so they should return the same identity if they are the same type.

    0 讨论(0)
  • 2020-11-28 05:50

    I like the function by EnricoGiampieri (above) but there is a simpler version using all_equal from the "Itertools recipes" section of the itertools docs:

    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)
    

    All of these recipes are packaged in more_itertools:

    Substantially all of these recipes and many, many others can be installed from the more-itertools project found on the Python Package Index:

    pip install more-itertools

    The extended tools offer the same high performance as the underlying toolset. The superior memory performance is kept by processing elements one at a time rather than bringing the whole iterable into memory all at once. Code volume is kept small by linking the tools together in a functional style which helps eliminate temporary variables. High speed is retained by preferring “vectorized” building blocks over the use of for-loops and generators which incur interpreter overhead.

    from more_itertools import all_equal
    
    all_equal(map(type, iterable))
    

    or with isinstance and a known type int (as per the original question)

    all_equal(map(lambda x: isinstance(x, int), iterable))
    

    These two ways are more concise than Enrico's suggestion and handle 'void iterators' (e.g. range(0)) just as Enrico's function does.

    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
    
    0 讨论(0)
提交回复
热议问题