Are Python's list comprehensions an efficient way to solve the task?

WBOY
Release: 2023-04-13 22:19:01
forward
1481 people have browsed it

Are Python's list comprehensions an efficient way to solve the task?

Python is an extremely diverse and powerful programming language! When a problem needs to be solved, it has different approaches.

Advantages of list analysis

  • Saves more time and space than loops.
  • Requires fewer lines of code.
  • Iterative statements can be converted into formulas.

How to create a list in Python

List comprehension is a syntax structure that creates a list based on an existing list. Let’s look at the different implementations of creating lists

Loops

Loops are the traditional way of creating lists. No matter what kind of loop you use. To create a list this way, you should:

  1. Instantiate an empty list.
  2. Loop through the elements of an iterable (such as range).
  3. Append each element to the end of the list.
numbers = []
for number in range(10):
numbers.append(number)
print(numbers)
Copy after login

Output:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Copy after login
Copy after login

In this example, you instantiate an empty list of numbers. Then use a for loop to iterate over range(10) and append each number to the end of the list using the append() method.

map() Object

map() is another way to create a list. You need to pass map() a function and an iterable object, after which it creates an object. This object contains the output obtained by executing each iteration element using the specified function.

For example, we will be presented with the task of adding VAT to the price of certain products.

VAT_PERCENT = 0.1# 10%
def add_vat(price):
return price + (price * VAT_PERCENT)
prices = [10.03, 8.6, 32.85, 41.5, 22.64]
grand_prices = map(add_vat, prices)
print(grand_prices)
grand_prices = list(grand_prices)
print(grand_prices)
Copy after login

You have built the add_vat() function and created the prices iterable object. You pass both arguments to map() and collect the resulting map object grand_prices, or you can easily convert it to a list using list().

Output:

<map object at 0x7f18721e7400># map(add_vat, prices)
[11.03, 9.46, 36.14, 45.65, 24.9]# list(grand_prices)
Copy after login

List comprehension

Now, let’s take a look at the list comprehension method! This is indeed Pythonic and a better way to create lists. To see how powerful this approach is, let's rewrite the loop example with a single line of code.

numbers = [number for number in range(10)]
print(numbers)
Copy after login

Output

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Copy after login
Copy after login

As you can see, this is an incredible method! The list comprehension looks readable enough that you don't need to write more code than just one line.

To better understand the list, please look at the following syntax format:

new_list = [expression for member in iterable]
Copy after login
Copy after login

Which method is more efficient

Okay, we have learned how to use loops, map( ) and list comprehensions to create a list, the question "which method is more efficient" might come up in your mind. Let’s analyze it!

import random
import timeit
VAT_PERCENT = 0.1
PRICES = [random.randrange(100) for x in range(100000)]
def add_vat(price):
return price + (price * VAT_PERCENT)
def get_grand_prices_with_map():
return list(map(add_vat, PRICES))
def get_grand_prices_with_comprehension():
return [add_vat(price) for price in PRICES]
def get_grand_prices_with_loop():
grand_prices = []
for price in PRICES:
grand_prices.append(add_vat(price))
return grand_prices
print(timeit.timeit(get_grand_prices_with_map, number=100))
print(timeit.timeit(add_grand_prices_with_comprehension, number=100))
print(timeit.timeit(get_grand_prices_with_loop, number=100))
Copy after login

Output:

0.9833468980004909# with_map
1.197223742999995 # with_comprehension
1.3564663889992516# with_loop
Copy after login

As we can see now, the best way to create a list is map(), the second best way is the list comprehension, and finally the loop .

However, the choice of method should depend on what you want to achieve.

  • Using map() can make your code more efficient.
  • Using loops can make the code ideas clearer.
  • Using list comprehensions can make your code more compact and efficient. This is the best way to create a list because it is the most readable.

Advanced Analytical Formulas

Conditional Logic

Earlier, I showed you this formula:

new_list = [expression for member in iterable]
Copy after login
Copy after login

The formula may be a little incomplete . A more complete description of analytical expressions adds support for optional conditions. The most common way to add conditional logic to a list comprehension is to add the conditional at the end of the expression:

new_list = [expression for member in iterable (if conditional)]
Copy after login

Here, your conditional statement is right inside the right bracket.

Conditions are important because they allow list comprehensions to filter out unwanted values, which can also be done by calling filter() in the general case:

numbers = [number for number in range(20) if number % 2 == 0]
print(numbers)
Copy after login

Output:

[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
Copy after login

As you can see, this analytical expression collects numbers that are divisible by 2 and have no remainder.

If you need a more complex filter, you can even move the conditional logic into a separate function.

def is_prime(number):
if number > 1:
for el in range(2, int(number/2)+1):
if (number % el) == 0:
return False
else:
return True
numbers = [number for number in range(20) if is_prime(number)]
print(numbers)
Copy after login

Output:

[2, 3, 5, 7, 11, 13, 17, 19]
Copy after login

You construct is_prime(number) to determine if a number is prime and return a boolean. Next, you should add the function to the condition of the analytic expression.

This formula allows you to choose from several possible output options using conditional logic. For example, you have a product price list, if there are negative numbers, you should convert them to positive numbers:

price_list = [1.34, 19.01, -4.2, 6, 8.78, -1,1]
normalized_price_list = [price if price > 0 else price*-1 for price in price_list]
print(normalized_price_list)
Copy after login

Output:

[1.34, 19.01, 4.2, 6, 8.78, 1,1]
Copy after login
Copy after login

Here, your expression price has a conditional statement , if price > 0 else price*-1. This tells Python to output the price value if the price is positive, but to convert the price to a positive value if the price is negative. This feature is powerful, and it is really useful to think of conditional logic as its own function:

def normalize_price(price):
return price if price > 0 else price*-1
price_list = [1.34, 19.01, -4.2, 6, 8.78, -1,1]
normalized_price_list = [normalize_price(price) for price in price_list]
print(normalized_price_list)
Copy after login

Output:

[1.34, 19.01, 4.2, 6, 8.78, 1,1]
Copy after login
Copy after login

Set parses

You can also create A set analytical expression! It's basically the same as a list comprehension. The difference is that set expressions do not contain duplicates. You can create set parses by using curly braces instead of square brackets:

string = "Excellent"
unique_string = {letter for letter in string}
print(unique_string)
Copy after login

Output:

{"E", "e", "n", "t", "x", "c", "l"}
Copy after login

你的集合解析式只包含唯一的字母。这与列表不同,集合不保证项目将以特定顺序存储数据。这就是为什么集合输出的第二个字母是 e,即使字符串中的第二个字母是 x。

字典解析式

字典解析式也是是类似的,但需要定义一个键:

string = "Words are but wind"
word_order = {el: ind+1 for ind, el in enumerate(string.split())}
print(word_order)
Copy after login

输出:

{"Words": 1, "are": 2, "but": 3, "wind": 4}
Copy after login

要创建 word_order 字典,请在表达式中使用花括号 ({}) 以及键值对 (el: ind+1)。

海象运算符

Python 3.8 中引入的海象运算符允许您一次解决两个问题:为变量赋值,返回该值。

假设您需要对将返回温度数据的 API 应用十次。您想要的只是 100 华氏度以上的结果。而每个请求可能都会返回不同的数据。在这种情况下,没有办法在 Python 中使用列表解析式来解决问题。可迭代成员(如果有条件)的公式表达式无法让条件将数据分配给表达式可以访问的变量。

海象运算符解决了这个问题。它允许您在执行表达式的同时将输出值分配给变量。以下示例显示了这是如何实现的,使用 get_weather_data() 生成伪天气数据:

import random
def get_weather_data():
return random.randrange(90, 110)
hot_temps = [temp for item in range(20) if (temp := get_weather_data()) >= 100]
print(hot_temps)
Copy after login

输出:

[108, 100, 106, 103, 108, 106, 103, 104, 109, 106]
Copy after login

什么时候不要使用解析式

列表解析式非常有用,它可以帮助您编写清晰且易于阅读和调试的代码。但在某些情况下,它们可能会使您的代码运行速度变慢或使用更多内存。如果它让您的代码效率更低或更难理解,那么可以考虑选择另一种方式。

注意嵌套的解析式

可以通过嵌套解析式以创建列表、字典和集合的组合集合(译者注:这个集合不是指 set 对象类型,而是 collection,泛指容器)。例如,假设一家公司正在跟踪一年中五个不同城市的收入。存储这些数据的完美数据结构可以是嵌套在字典解析式中的列表解析式。

cities = ['New York', 'Oklahoma', 'Toronto', 'Los Angeles', 'Miami']
budgets = {city: [0 for x in range(12)] for city in cities}
print(budgets)
Copy after login

输出:

{
"NewYork": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"Oklahoma": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"Toronto": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"LosAngeles": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"Miami": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
}
Copy after login

您使用字典解析式创建了 budgets 容器。该表达式是一个键值对,其中包含另一个解析式。此代码将快速生成城市中每个 city 的数据列表。

嵌套列表是创建矩阵的常用方法,通常用于数学目的。查看下面的代码块:

matrix = [[x for x in range(7)] for y in range(6)]
print(matrix)
Copy after login

输出:

[
[0, 1, 2, 3, 4, 5, 6],
[0, 1, 2, 3, 4, 5, 6],
[0, 1, 2, 3, 4, 5, 6],
[0, 1, 2, 3, 4, 5, 6],
[0, 1, 2, 3, 4, 5, 6],
[0, 1, 2, 3, 4, 5, 6]
]
Copy after login

外部列表解析式 [... for y in range(6)] 创建了六行,而内部列表解析式 [x for x in range(7)] 将用值填充这些行中的每一行。

到目前为止,每个嵌套解析式的目标都是真正且直观的。但是,还有一些其他情况,例如创建扁平化的嵌套列表,其中的逻辑可以使您的代码非常难以阅读。让我们看下面的例子,使用嵌套列表解析式来展平一个矩阵:

matrix = [
[0, 1, 0],
[1, 0, 1],
[2, 1, 2],
]
flat = [num for row in matrix for num in row]
print(flat)
Copy after login

输出:

[0, 1, 0, 1, 0, 1, 2, 1, 2]
Copy after login
Copy after login

扁平化矩阵的代码确实很简洁,但是太难理解了,您应该花点时间弄清楚它是如何工作的。另一方面,如果您使用 for 循环来展平相同的矩阵,那么您的代码将更加简单易读:

matrix = [
[0, 1, 0],
[1, 0, 1],
[2, 1, 2],
]
flat = []
for row in matrix:
for num in row:
flat.append(num)
print(flat)
Copy after login

输出:

[0, 1, 0, 1, 0, 1, 2, 1, 2]
Copy after login
Copy after login

现在,您可以看到代码一次遍历矩阵的一行,在移动到下一行之前取出该行中的所有元素。

虽然嵌套列表解析式可能看起来更具有 Python 风格,但对于能够编写出您的团队可以轻松理解和修改的代码来才是更加最重要的。当选择一个方法时,您应该根据解析式是有助于还是有损于可读性来做出相应的判断。

为大型数据集使用生成器

Python 中的列表解析式通过将整个列表存储到内存中来工作。对于小型至中型列表这通常很好。如果您想将前一千个整数相加,那么列表解析式将轻松地解决此任务:

summary = sum([x for x in range(1000)])
print(summary)
Copy after login

输出:499500

但是,如果您需要对十亿个数字求和呢?您可以尝试执行此操作,但您的计算机可能不会有响应。这是可能因为计算机中分配大量内存。也许您是因为计算机没有如此多的内存资源。

例如,你想要一些第一个十亿整数,那么让我们使用生成器!这可能多需要一些时间,但计算机应该可以克服它:

summary = sum((x for x in range(1000000000)))
print(summary)
Copy after login

输出:

499999999500000000
Copy after login

让我们来对比一下哪种方法是更优的!

import timeit
def get_sum_with_map():
return sum(map(lambda x: x, range(1000000000)))
def get_sum_with_generator():
return sum((x for x in range(1000000000)))
print(timeit.timeit(get_sum_with_map, number=100))
print(timeit.timeit(get_sum_with_generator, number=100))
Copy after login

输出:

4940.844053814# get_sum_with_map
3464.1995523349997# get_sum_with_generator
Copy after login

正如您所见,生成器比 map() 高效得多。

总结

本文向您介绍了列表解析式,以及如何使用它来解决复杂的任务,而不会使您的代码变得过于困难。

现在你:

  • Learned several alternative ways to create lists.
  • Find out the advantages of each method.
  • Can simplify loops and map() calls to list comprehensions.
  • Understood a way to add conditional logic to analytical expressions.
  • Can create sets and dictionary expressions.
  • Learned when not to use analytical expressions.

Thank you for reading this article till the end! If this post was helpful, please leave a comment and remember to hit "Follow" to make sure you don't miss my posts! Your activities are my joy! Good luck!

The above is the detailed content of Are Python's list comprehensions an efficient way to solve the task?. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:51cto.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template