📜 ⬆️ ⬇️

1000 + 1 way to determine if all items in the list are the same.

In life, we always have a choice, whether we know about it or not. The same thing happens in coding. There are many ways in which we can approach a specific task. We may not initially consider these methods or have no idea about them, but they exist. Being a programmer is not just knowing the language and the process of writing code. Very often it means to be the most creative version of yourself, considering even something that you have not thought about before. And on that note, I would like to introduce myself. Hello! My name is Alex, I am the founder of CheckiO , and I have long been engaged in the creative aspects of this project.

image

Our users have different levels of knowledge and experience in the field of coding, so I often see standard and more obvious approaches to solving problems. But from time to time I come across such unique and unusual solutions that they force me to re-learn the previously unknown subtleties of the language.

In this article I want to consider some solutions to one of the very simple tasks that, in my opinion, are the most interesting. The mission requires you to write a function that will determine whether all the elements of the array have the same value.

1. One of the first decisions that comes to mind is to compare the length of the list of source elements with how many times the first element is included in the list. If these values ​​are equal, then the list consists of the same elements. There is also a check whether the list is empty, since in this case it is also necessary to return True.
')
def all_the_same(elements): if len(elements) < 1: return True return len(elements) == elements.count(elements[0]) 

Or a more abbreviated version:

 def all_the_same(elements): return len(elements) < 1 or len(elements) == elements.count(elements[0]) 

2. This solution used a useful feature of Python - the ability to compare lists with just the comparison operator - '==' (unlike some other programming languages, where it is not so easy to do). Consider how this works:

 >>> [1, 1, 1] == [1, 1, 1] True >>> [1, 1, 0] == [0, 1, 1] False 

Another feature of the language is that it provides the ability to multiply the list by a number and the result of this operation will be a list in which all elements are copied the specified number of times. Let me show you some examples:

 >>> [1] * 3 [1, 1, 1] >>> [1] * 5 [1, 1, 1, 1, 1] >>> [1] * 0 [] >>> [1, 2] * 3 [1, 2, 1, 2, 1, 2] 

Thus, you can come to a simple solution - if you multiply an array of one first element from the source array by the length of this source array, you should again get the original array if all the elements of this array are the same.

 def all_the_same(elements): if not elements: return True return [elements[0]] * len(elements) == elements 

As in the previous case, you can shorten this solution:

 def all_the_same(elements): return not elements or [elements[0]] * len(elements) == elements 

3. This solution used the standard set () function . This function converts an object into a set in which, by definition, all elements must be unique. It looks like this:

 >>> elements = [1, 2, 5, 1, 5, 3, 2] >>> set(elements) {1, 2, 3, 5} 

If, as a result, the resulting set will consist of 1 or 0 elements, then all the elements in the initial list were the same or it was empty. The solution might look like this:

 def all_the_same(elements): return len(set(elements)) in (0, 1) 

or so:

 def all_the_same(elements): return len(set(elements)) <= 1 

A similar approach can be used with the NumPy module, which has a unique () function that works as follows:

 >>> from numpy import unique >>> a = [1, 2, 1, 2, 3, 1, 1, 1, 1] >>> unique(a) [1 2 3] 

As you can see, her work is very similar to set (), only in this case
object type changes - the list remains a list. The solution using this function looks like this:

 from numpy import unique def all_the_same(elements): return len(unique(elements)) <= 1 

4. Here is an example of a very original solution, in which, moreover, the name of this problem is played up with the help of the standard Python function - all () . The function all () returns True if all elements of the transferred list are True. For example:

 >>> all([1, 2, 0, True]) False #(0  true) >>> all([1, 2, None, True]) False #(None  true) >>> all([1, 2, False, True]) False >>> all([1, 2, 0.1, True]) True 

First, the variable first is assigned the value of the first element of the list, and rest is the list of all other elements except the first. Then True or False values ​​are added to the_same tuple, depending on whether the next item in the list is rest and equal to the first item in the source list. After that, the function all () returns True if the_same consists only of the 'True' elements, and False if there is at least one 'False' element in the tuple.

 def all_the_same(elements): try: first, *rest = elements except ValueError: return True the_same = (x == first for x in rest) return all(the_same) 

The ValueError exception will be raised only if the array is empty. But we can do a more familiar check:

 def all_the_same(elements): if not elements: return True first, *rest = elements the_same = (x == first for x in rest) return all(the_same) 

5. The next solution is very similar to the previous one. There is only a small correction in it - the first and the other elements from the original list are separated using an iterator. The iter () function creates an iterator from the passed list, and the next () function takes the next element from it (that is, the first one - on the first call). If we print out the elements in el and first, we see the following:

 >>> el = iter([1, 2, 3]) >>> first = next(el, None) >>> print(first) 1 >>> for i in el: >>> print(i) 2 3 

Otherwise, this solution is similar to the previous one, except that we do not need to check whether the list is empty or not.

 def all_the_same(elements): el = iter(elements) first = next(el, None) return all(element == first for element in el) 

6. One of the creative approaches to solving this problem is the rearrangement of elements. We swap the items and check that the list has not changed because of this. This tells us that all the items in the list are the same. Here are a couple of examples of this approach:

 def all_the_same(elements): return elements[1:] == elements[:-1] 

and

 def all_the_same(elements): return elements == elements[1:] + elements[:1] 

It is also worth noting that it is possible to compare arrays elementwise using the zip () function . Consider this on the example of the following solutions.

7. The zip () function combines every i-th element of a single object with the i-th element of the rest until the shortest object ends.

 >>> x = [1, 2, 3] >>> y = [10, 11] >>> list(zip(x, y)) [(1, 10), (2, 11)] 

As you can see, despite the fact that x consists of three elements, only two were used, since the shortest object - in this case, y - consists of only 2 elements.

The solution below works as follows: first, a second list is created (elements [1:]), which is equal to the original list, but without the first element. Then, elements from these two lists are compared in turn, and as a result of each such comparison, we get True or False. Then the all () function returns the result of processing this set of True and False.

 def all_the_same(elements): return all(x == y for x, y in zip(elements, elements[1:])) 

Suppose our original list is elements = [2, 2, 2, 3]. Then using zip (), we will combine the complete list ([2, 2, 2, 3]) and the list without the first element ([2, 2, 3]) in the following way: [(2, 2), (2, 2 ), (2, 3)], comparisons of elements among themselves will transfer to the all () function a set [True, True, False] and as a result we will get False, which is the correct answer, since not all elements are the same in the original list.

8. The following decision was quite curious. It used the groupby () iterator , which works in this way - compares each i-th element with (i-1) -th and if elements are equal - moves on, and if not equal - leaves element (i-1) in the final list and continues the comparison with the next item. In practice, it looks like this:

 >>> from itertools import groupby >>> elements = [1, 1, 1, 2, 1, 1, 1, 2] >>> for key, group in groupby(elements): >>> print(key) 1 2 1 2 

As you can see, there are only those elements that differ from the element at the next position (elements [0], elements [1], elements [4] and elements [5] have been excluded).

In this solution, the function using the groupby () iterator adds one (1) to the list each time the next element in the original list differs from the previous one. Thus, if the initial list contains 0 elements or all elements are equal, the sum (sum (1 for _ in groupby (elements))) will be 0 or 1 — that is, in any case, less than 2, which is indicated in the solution.

 from itertools import groupby def all_the_same(elements): return sum(1 for _ in groupby(elements)) < 2 

9. Another creative solution that uses one of the standard Python modules - collections . Counter creates a dictionary where it stores information about the number of each item in the source list. Let's see how it works:

 >>> from collections import Counter >>> a = [1, 1, 1, 2, 2, 3] >>> Counter(a) Counter({1: 3, 2: 2, 3: 1}) 

Accordingly, if the length of this dictionary is 2 or more, there will be at least 2 different elements in the source list and not all elements are the same.

 def all_the_same(elements): from collections import Counter return not len(list(Counter(elements))) > 1 

10. This solution is built on the same logic as solution No. 7, but the eq () and starmap () functions are used. We will understand how they work:

 >>> from operator import eq >>> eq(1, 2) False 

In essence, the eq () function does the same as “==” - compares two objects and returns True if they are equal and False otherwise (eq is short for equivalent). However, note that a function is an object and it can be, for example, passed as an argument to another function, which was done in the solution described below.

The starmap () function creates an iterator that applies another function to the list of objects. It is used when objects are already grouped into tuples. For example:

 >>> import math >>> from itertools import starmap >>> list(starmap(math.pow, [(1, 2), (3, 4)])) [1.0, 81.0] 

As you can see, the math.pow () function specified once, thanks to the starmap () function, was applied twice - to both sets of objects (1 ** 2 = 1.0, 3 ** 4 = 81.0)

Simplified, the starmap () function for this example can be represented as a loop:

 import math elements = [(1, 2), (3, 4)] result = [] for i in elements: result.append(math.pow(i[0], i[1])) 

The solution using the functions described earlier looks like this:

 from operator import eq from itertools import starmap def all_the_same(elements): return all(starmap(eq, zip(elements, elements[1:]))) 

Conclusion

So, we looked at some clever solutions that relate to one of the simplest puzzles. With all the desire, I have no idea how to begin to describe the number of unique approaches that our users use to solve other interesting and more complex tasks. I hope you enjoyed reading this article just as much as I did at the time of writing it. I look forward to your feedback. Was this helpful to you? How would you solve this problem?

Translation of the article “The Same in Python” , published on the blog “The Mouse Vs. The Python .

Source: https://habr.com/ru/post/358284/


All Articles