📜 ⬆️ ⬇️

Python: collections, part 2/4: indexing, slicing, sorting

Part 1Part 2Part 3Part 4
image This article is a continuation of my article " Python: collections, part 1: classification, general approaches and methods, conversion ".

In this article, we will continue to learn the general principles of working with standard collections (the collections module is not covered in it) Python.

For whom: for Python learners who already have an initial understanding of the collections and work with them, who want to systematize and deepen their knowledge, put them into a coherent picture.
')

TABLE OF CONTENTS:


  1. Indexing
  2. Slices
  3. Sorting

1. Indexing


1.1 Indexed Collections


Consider indexed collections (they are also called sequences - sequences) - a list (list), a tuple (tuple), a string (string).

Under indexing is meant that the elements of the collection are arranged in a certain order, each element has its own index from 0 (that is, the first element has an index not 1 but 0) up to an index one less than the length of the collection (ie len (mycollection )-one).

1.2 Getting the value by index


For all indexed collections, you can get the value of an element by its index in square brackets. Moreover, you can set a negative index, which means that we will find the element from the end, counting the reverse order.

When specifying a negative index, the last element has index -1, the penultimate -2 and so on until the first element whose index is equal to the length of the collection with a negative sign, that is (-len (mycollection).
itemsabcde
indexes0 (-5)14)2 (-3)3 (-2)4 (-1)
my_str = "abcde" print(my_str[0]) # a -   print(my_str[-1]) # e -   print(my_str[len(my_str)-1]) # e -       print(my_str[-2]) # d -   

Our collections can have several levels of nesting, like the list of lists in the example below. To go deeper, a second pair of square brackets is placed, and so on.

 my_2lvl_list = [[1, 2, 3], ['a', 'b', 'c']] print(my_2lvl_list[0]) # [1, 2, 3] -   —    print(my_2lvl_list[0][0]) # 1 —      print(my_2lvl_list[1][-1]) #  —      

1.3 Changing the list item by index


Since the tuples and strings are immutable collections, we can only take elements by index, but not change them:

 my_tuple = (1, 2, 3, 4, 5) print(my_tuple[0]) # 1 my_tuple[0] = 100 # TypeError: 'tuple' object does not support item assignment 

But for the list, if taking an element by index is located on the left side of the expression, and then comes the assignment operator =, then we set the new value to the element with this index.

 my_list = [1, 2, 3, [4, 5]] my_list[0] = 10 my_list[-1][0] = 40 print(my_list) # [10, 2, 3, [40, 5]] 

UPD: Note: For such an assignment, the item must already exist in the list, you cannot thus add an item to a nonexistent index.

 my_list = [1, 2, 3, 4, 5] my_list[5] = 6 # IndexError: list assignment index out of range 


2 slices


2.1 Slice Syntax


Very often, you need to get more than one element, and some of their set is limited to certain simple rules - for example, the first 5 or last three, or every second element - in such tasks, instead of iterating through the loop, it is much more convenient to use the so-called slice (slice slicing).

It should be remembered that by taking an element by index or slice, we do not change the original collection, we simply copied a part of it for further use (for example, adding it to another collection, printing, some calculations). Since the collection itself does not change - this applies to both mutable (list) and immutable (string, tuple) sequences.

The slice syntax is similar to that for indexing, but in square brackets instead of a single value, 2-3 is indicated with a colon:

 my_collection[start:stop:step] # ,    

Features of the cut:



Examples of slices in the form of a table:


image

Code of examples from the table
 col = 'abcdefg' print(col[:]) # abcdefg print(col[::-1]) # gfedcba print(col[::2]) # aceg print(col[1::2]) # bdf print(col[:1]) # a print(col[-1:]) # g print(col[3:4]) # d print(col[-3:]) # efg print(col[-3:1:-1]) # edc print(col[2:5]) # cde 

2.2. Named slices


To get rid of the "magic constants", especially in the case when the same slice must be used repeatedly, you can set constants with named slices using the special function slice () ()

Note: Non does not correspond to the omitted default value. That is, [: 2] becomes slice (None, 2), and [1 :: 2] becomes slice (1, None, 2).

 person = ('Alex', 'Smith', "May", 10, 1980) NAME, BIRTHDAY = slice(None, 2), slice(2, None) #     #         print(person[NAME]) # ('Alex', 'Smith') print(person[BIRTHDAY]) # ('May', 10, 1980) 

 my_list = [1, 2, 3, 4, 5, 6, 7] EVEN = slice(1, None, 2) print(my_list[EVEN]) # [2, 4, 6] 

2.3 Changing the list with a slice


The important point on which attention is not always focused is that with the help of a slice you can not only get a copy of the collection, but in the case of a list you can also change the values ​​of the elements, delete and add new ones.

We illustrate this with examples below:



2.4 Going beyond the index


Addressing by index is essentially a special case of a slice, when we refer to only one element, and not a range. But there is a very important difference in handling the situation with the missing element with the desired index.

Accessing a non-existent collection index causes an error:

 my_list = [1, 2, 3, 4, 5] print(my_list[-10]) # IndexError: list index out of range print(my_list[10]) # IndexError: list index out of range 

And if the cut boundaries extend beyond the boundaries of the collection, no error occurs:

 my_list = [1, 2, 3, 4, 5] print(my_list[0:10]) # [1, 2, 3, 4, 5] —     print(my_list[10:100]) # [] -    —    print(my_list[10:11]) # [] -  1   -  ,   


Note : For those cases when the slice functional is not enough and more complex samples are required, you can use the syntax of expression-generators, which are discussed in article 4 of the cycle .

3 Sorting collection items


Sorting elements of the collection is an important and demanded function that is constantly encountered in ordinary tasks. There are several features that are not always focused on, but which are very important.

3.1 sorted function ()


We can use the sorted () function to list the sorted elements of any collection for further processing or output.


 my_list = [2, 5, 1, 7, 3] my_list_sorted = sorted(my_list) print(my_list_sorted) # [1, 2, 3, 5, 7] my_set = {2, 5, 1, 7, 3} my_set_sorted = sorted(my_set, reverse=True) print(my_set_sorted) # [7, 5, 3, 2, 1] 

An example of sorting the list of strings by the length len () of each element:

 my_files = ['somecat.jpg', 'pc.png', 'apple.bmp', 'mydog.gif'] my_files_sorted = sorted(my_files, key=len) print(my_files_sorted) # ['pc.png', 'apple.bmp', 'mydog.gif', 'somecat.jpg'] 

3.2 reversed () function


The reversed () function is used for sequences and works differently:


 my_list = [2, 5, 1, 7, 3] my_list_sorted = reversed(my_list) print(my_list_sorted) # <listreverseiterator object at 0x7f8982121450> print(list(my_list_sorted)) # [3, 7, 1, 5, 2] print(my_list[::-1]) # [3, 7, 1, 5, 2] -       

3.3 List methods. sort () and. reverse ()


The list (and only it) has special methods .sort () and .reverse () which do the same thing as the corresponding sorted () and reversed () functions, but at the same time:


 my_list = [2, 5, 1, 7, 3] my_list.sort() print(my_list) # [1, 2, 3, 5, 7] 

Note: This is a common mistake of beginners, which is not an error for the interpreter, but does not lead to the result that they want to get.

 my_list = [2, 5, 1, 7, 3] my_list = my_list.sort() print(my_list) # None 

3.4 Features of dictionary sorting


Sorting the dictionary has its own characteristics, due to the fact that the dictionary element is a pair of key: value.

UPD: Also, do not forget that speaking of the sorting of the dictionary, we mean the sorting of the data obtained from the dictionary for output or save to an indexed collection. Saving data in the standard dictionary itself will not work; they are in it, like other non-indexed collections, in random order.


 my_dict = {'a': 1, 'c': 3, 'e': 5, 'f': 6, 'b': 2, 'd': 4} mysorted = sorted(my_dict) print(mysorted) # ['a', 'b', 'c', 'd', 'e', 'f'] mysorted = sorted(my_dict.items()) print(mysorted) # [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5), ('f', 6)] mysorted = sorted(my_dict.values()) print(mysorted) # [1, 2, 3, 4, 5, 6] 

Separate difficulties can be caused by sorting the dictionary not by keys, but by values , if we do not just need a list of values, and it is to output pairs in the sort order by value.

To solve this problem, as a special sorting function, you can pass the lambda function lambda x: x [1] which of the tuples obtained at each stage (key, value) will be taken to sort the second element of the tuple.

 population = {"Shanghai": 24256800, "Karachi": 23500000, "Beijing": 21516000, "Delhi": 16787941} #    : population_sorted = sorted(population.items(), key=lambda x: x[1]) print(population_sorted) # [('Delhi', 16787941), ('Beijing', 21516000), ('Karachi', 23500000), ('Shanghai', 24256800)] 


UPD by ShashkovS : 3.5 Additional information on using the key parameter when sorting


Suppose we have a list of tuples of names of parts and their values.
We need to sort it first by the name of the parts, and the same parts in descending price.

 shop = [('', 1200), ('', 1000), ('', 300), ('', 100), ('', 1500), ('', 12000), ('', 2000), ('', 200), ('', 2700)] def prepare_item(item): return (item[0], -item[1]) shop.sort(key=prepare_item) 

Sort result
 for det, price in shop: print('{:<10} : {:>5}.'.format(det, price)) #  : 1200. #  : 2000. #  : 100. #  : 12000. #  : 2700. #  : 1500. #  : 300. #  : 1000. #  : 200. 

Before comparing two elements of the list, the prepare_item function was applied to them, which changed the sign of the cost (the function is applied exactly once to each element. As a result, with the same first value, the sorting by the second occurred in the reverse order.

In order not to produce utilitarian functions, instead of using a third-party function, the same effect can be achieved using the lambda function.

 #      shop.sort(key=lambda x: (x[0], -x[1])) 

Additional details and examples of using the key parameter:

UPD by ShashkovS : 3.6 Stability Sort


Suppose you need to sort the data first by column A in ascending order, then in column B in descending order, and finally in column C again in ascending order.

If the data in column B is numeric, then using the appropriate function in the key, you can change the sign of the elements of B, which will lead to the desired result.
And if all the data text? There is such an opportunity.
The fact is that sorting sorting in Python is stable (since Python 2.2), that is, it does not change the order of “identical” elements.

Therefore, you can simply sort three times according to different keys:
 data.sort(key=lambda x: x['C']) data.sort(key=lambda x: x['B'], reverse=True) data.sort(key=lambda x: x['']) 

More information on sorting resilience and examples: wiki.python.org/moin/HowTo/Sorting#Sort_Stability_and_Complex_Sorts (in English).
Part 1Part 2Part 3Part 4

I invite you to discuss:


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


All Articles