List comprehension methods in Python

Nicola Andrei-George
6 min readJul 11, 2024

--

Photo by Pankaj Patel on Unsplash

The need for Python

If no already obvious, Python is a language of comprehensions itself as it supports modularity, object-oriented programming, functional programming, as well as the lack of any(or all) of them, so there is no restriction like Java where everything is an object or like Haskell where everything is a function. Depending on the purpose, you are the architect of the code.

Compared to C++ we may rewrite 9 lines of code in only 2 lines.

C++

#include <iostream>
using namespace std;

int main() {
int a, b, c;
cin >> a >> b >> c;
cout << a + b + c << endl;
return 0;
}

Python

a, b, c = map(int, input().split())
print(a + b + c)

Lists in python

https://cdn.analyticsvidhya.com/wp-content/uploads/2021/07/38787wallpaper.png

The basic data types in Python are:

  • integer
  • boolean
  • floating-point
  • string

In contrast to C/C++, the arrays are not statically typed, so you don’t need to know the type of the values that are going to be stored; of course the array will take up enough memory to accommodate any possible type — the equivalent of a void pointer from C. The arrays are in 98% of cases implemented using lists, and for matrices are used …. lists in lists! How? Well, below is a code example

Python code

array1 = [1, 5, 3, 0, 5]
array2 = [1, 2, 3, 4, 5]
matrix1 = [[1, 2, 3],
[5, 2, 4],
[5, 1, 3]]
matrix2 = [[5, 2, 3],
[6, 2, 4],
[2, 3, 2]]
print(array1)
print(matrix2)

[1, 5, 3, 0, 5]
[[5, 2, 3], [6, 2, 4], [2, 3, 2]]

List declaration

Python supports a wide range of declaration and initialization methods based on tuples, lists, dictionaries, ranges and logical conditions as filters.

Splitting a natural interval in even and odd numbers

l1 = [i for i in range(1, 20)]
l2 = [i for i in l1 if i % 2 == 0]
l3 = [i for i in l1 if i % 2 == 1]
print(l1)
print(l2)
print(l3)

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
[2, 4, 6, 8, 10, 12, 14, 16, 18]
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]

Dividing N natural numbers in classes of remainder modulo K

k = 10
array = [i for i in range(1, 31)]
remainders = [[i for i in array if i % k == j] for j in range(k)]
print(array)
print(remainders)

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
[[10, 20, 30], [1, 11, 21], [2, 12, 22], [3, 13, 23], [4, 14, 24], [5, 15, 25], [6, 16, 26], [7, 17, 27], [8, 18, 28], [9, 19, 29]]

Applying a lambda function over the elements

ar = [13, 24, 52, 12, 83, 84, 25, 39]
def hash_function(x: int) -> int:
a = x >> 3
b = x % 8
return (a + 2 * b) % 16
hash_ar = [hash_function(i) for i in ar]
print(hash_ar)

[11, 3, 14, 9, 0, 2, 5, 2]

Reverse all strings from a list

words = ["Medium", "is", "the", "coolest", "tech", "blog", "ever"]
reversed_words = [word[::-1] for word in words]
print(reversed_words)

[‘muideM’, ‘si’, ‘eht’, ‘tselooc’, ‘hcet’, ‘golb’, ‘reve’]

Apply XOR with ease on ciphertext and key(and many crypto applications as well)

# suppose we know the secret 'aresdv' and a random-valued cyphertext
cyphertext = [32, 28, 1, 1, 1, 31]
key = list(ord(i) for i in 'aresdv')
# now we can compute the plaintext with ease
plaintext = [i^j for i, j in zip(cyphertext, key)]
print(plaintext)
# and convert the ascii to characters
plaintext_ascii = [chr(i) for i in plaintext]
print(plaintext_ascii)

[65, 110, 100, 114, 101, 105]
[‘A’, ’n’, ‘d’, ‘r’, ‘e’, ‘i’]

than checking it out everything was correct we can compute back the cyphertext knowing the actual plaintext

cypher_again = [ord(chr(i^j)) for i, j in zip(plaintext, key)]
print(cypher_again)

[32, 28, 1, 1, 1, 31]

Applying functional programming

filter

words = {'I', 'am', 'a', 'programmer', 'writing', 'on', 'medium'}
small_words = filter(lambda x: True if len(x) < 5 else False, words)
for idx, w in enumerate(small_words):
print(f'{idx}: {w}', end=' ')
# OUTPUT:
# 0:am 1:on 2:a 3:I

Based on a bigger list we can create a newer one filtering it in concordance with a criteria of our choice, in this case only the words that we consider sufficient enough to be called small.

map

n = {1, 2, 3, 4, 5, 6}
squared_n = map(lambda x: x**2, n)
for idx, n2 in enumerate(squared_n):
print(f'{idx}:{n2}', end=' ')
# OUTPUT:
# 0:1 1:4 2:9 3:16 4:25 5:36

What this actually does is explained mathematically right below

map function over a function f(x)

Obviously, the square function is just one of the most common ones, but imagine that you could have just another list or a tuple as the argument and the output could have been another filtered list or just the sum of the even elements.

reduce

One very import aspect that you must consider especially when falling for using reduce, that is the order of elements. If you want it to be conserved you must use lists or tuples! In the case of sets(the structure which doesn’t care for order or duplicates, you may get random outputs sometimes:

import functools
set_words = {'Let\'s', 'make', 'a', 'sentence', 'out', 'of', 'words'}
tuple_words = ('Let\'s', 'make', 'a', 'sentence', 'out', 'of', 'words')
list_words = ['Let\'s', 'make', 'a', 'sentence', 'out', 'of', 'words']

set_sentence = functools.reduce(lambda x, y: x + ' ' + y, set_words)
tuple_sentence = functools.reduce(lambda x, y: x + ' ' + y, tuple_words)
list_sentence = functools.reduce(lambda x, y: x + ' ' + y, list_words)
print('Output for ' + str(type(set_words)) + ': ' + set_sentence,
'Output for ' + str(type(tuple_words)) + ': ' + tuple_sentence,
'Output for ' + str(type(list_words)) + ': ' + list_sentence,
end='', sep='\n===================================================\n')
# OUTPUT:
# Output for <class 'set'>: of words out a Let's sentence make
# ===================================================
# Output for <class 'tuple'>: Let's make a sentence out of words
# ===================================================
# Output for <class 'list'>: Let's make a sentence out of words

In contrast to this case of factorizing numbers up where a set is undesirable because of possible repetitions of specific numbers:

set_factors = {2, 3, 4, 2}
tuple_factors = (2, 3, 4, 2)
list_factors = [2, 3, 4, 2]

set_product = functools.reduce(lambda x, y: x*y, set_factors)
tuple_product = functools.reduce(lambda x, y: x*y, tuple_factors)
list_product = functools.reduce(lambda x, y: x*y, list_factors)
print('Output for ' + str(type(set_factors)) + ': ' + str(set_product),
'Output for ' + str(type(tuple_factors)) + ': ' + str(tuple_product),
'Output for ' + str(type(list_factors)) + ': ' + str(list_product),
end='', sep='\n===================================================\n')
# OUTPUT:
# Output for <class 'set'>: 24
# ===================================================
# Output for <class 'tuple'>: 48
# ===================================================
# Output for <class 'list'>: 48

In conclusion, python works just fine as it is with lots of useful features for you to code, the big responsibility is to know what exactly you choose and the reasons back the curtain.

If you liked it…

  • Please consider clapping and following me! 👏
  • If you have suggestions/preferred topics you want me to write about, tell me down in a comment
  • Thanks anyways, if you reached so far reading my article!

--

--

Nicola Andrei-George

just your regular computer science student passionate about AI and satellite communication