ホームページ  >  記事  >  バックエンド開発  >  Python のリスト内包表記はタスクを解決する効率的な方法ですか?

Python のリスト内包表記はタスクを解決する効率的な方法ですか?

WBOY
WBOY転載
2023-04-13 22:19:011483ブラウズ

Python のリスト内包表記はタスクを解決する効率的な方法ですか?

Python は非常に多様で強力なプログラミング言語です。問題を解決する必要がある場合、さまざまなアプローチがあります。

リスト分析の利点

  • ループよりも時間とスペースを節約できます。
  • 必要なコード行が少なくなります。
  • 反復ステートメントは数式に変換できます。

Python でリストを作成する方法

リスト内包表記は、既存のリストに基づいてリストを作成する構文構造です。リスト作成のさまざまな実装を見てみましょう

ループ

ループはリストを作成する従来の方法です。どのようなループを使用しても構いません。この方法でリストを作成するには、次のことを行う必要があります:

  1. 空のリストをインスタンス化します。
  2. 反復可能要素 (範囲など) をループします。
  3. 各要素をリストの末尾に追加します。
numbers = []
for number in range(10):
numbers.append(number)
print(numbers)

出力:

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

この例では、空の数値リストをインスタンス化します。次に、for ループを使用して range(10) を反復し、append() メソッドを使用してリストの末尾に各数値を追加します。

map() オブジェクト

map() はリストを作成する別の方法です。 map() に関数と反復可能なオブジェクトを渡し、その後オブジェクトを作成する必要があります。このオブジェクトには、指定された関数を使用して各反復要素を実行することによって取得された出力が含まれます。

たとえば、特定の製品の価格に VAT を追加するというタスクが表示されます。

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)

add_vat() 関数を構築し、価格の反復可能オブジェクトを作成しました。両方の引数を map() に渡し、結果のマップ オブジェクト grand_prices を収集するか、list() を使用してそれをリストに簡単に変換できます。

出力:

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

リスト内包表記

それでは、リスト内包表記の方法を見てみましょう。これは確かに Python 的であり、リストを作成するためのより良い方法です。このアプローチがどれほど強力であるかを確認するために、ループの例を 1 行のコードで書き直してみましょう。

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

出力

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

ご覧のとおり、これは素晴らしい方法です。リスト内包表記は十分読みやすいので、1 行以上のコードを記述する必要はありません。

リストをよりよく理解するには、次の構文形式を参照してください。

new_list = [expression for member in iterable]

どの方法がより効率的か

わかりました。ループ、map( の使用方法を学びました。 ) とリスト内包表記を使ってリストを作成すると、「どちらの方法がより効率的か」という疑問が浮かぶかもしれません。分析してみましょう!

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))

出力:

0.9833468980004909# with_map
1.197223742999995 # with_comprehension
1.3564663889992516# with_loop

これでわかるように、リストを作成する最良の方法は map() で、2 番目に良い方法はリストの内包表記、そして最後にループです。

ただし、方法の選択は、何を達成したいかによって異なります。

  • map() を使用すると、コードをより効率的にすることができます。
  • ループを使用すると、コードのアイデアがより明確になります。
  • リスト内包表記を使用すると、コードをよりコンパクトで効率的にすることができます。これは最も読みやすいため、リストを作成する最適な方法です。

高度な分析式

条件付きロジック

前に、次の式を示しました。

new_list = [expression for member in iterable]

この式は少し不完全かもしれません。分析式のより完全な説明により、オプションの条件のサポートが追加されました。リスト内包表記に条件ロジックを追加する最も一般的な方法は、式の最後に条件を追加することです。

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

ここで、条件ステートメントは右括弧の中にあります。

条件は、リスト内包表記で不要な値を除外できるため重要です。これは、一般的な場合に filter() を呼び出して行うこともできます:

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

出力:

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

ご覧のとおり、この分析式は 2 で割り切れて余りのない数値を集めます。

より複雑なフィルターが必要な場合は、条件ロジックを別の関数に移動することもできます。

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)

出力:

[2, 3, 5, 7, 11, 13, 17, 19]

is_prime(number) を構築して、数値が素数かどうかを判断し、ブール値を返します。次に、分析式の条件に関数を追加する必要があります。

この式を使用すると、条件付きロジックを使用して、可能ないくつかの出力オプションから選択できます。たとえば、製品の価格リストがあるとします。負の数値がある場合は、正の数値に変換する必要があります。

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)

出力:

[1.34, 19.01, 4.2, 6, 8.78, 1,1]

ここで、式の Price には条件文が含まれています。価格 > 0 の場合、そうでない場合は価格*-1。これは、価格が正の場合は価格値を出力し、価格が負の場合は価格を正の値に変換するように Python に指示します。この機能は強力であり、条件付きロジックを独自の関数として考えると非常に便利です。

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)

出力:

[1.34, 19.01, 4.2, 6, 8.78, 1,1]

Set parses

セットを作成することもできます。分析的な表現!基本的にはリスト内包表記と同じです。違いは、set 式には重複が含まれないことです。角括弧の代わりに中括弧を使用してセット解析を作成できます。

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

出力:

{"E", "e", "n", "t", "x", "c", "l"}

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

字典解析式

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

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

输出:

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

要创建 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)

输出:

[108, 100, 106, 103, 108, 106, 103, 104, 109, 106]

什么时候不要使用解析式

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

注意嵌套的解析式

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

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

输出:

{
"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]
}

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

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

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

输出:

[
[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]
]

外部列表解析式 [... 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)

输出:

[0, 1, 0, 1, 0, 1, 2, 1, 2]

扁平化矩阵的代码确实很简洁,但是太难理解了,您应该花点时间弄清楚它是如何工作的。另一方面,如果您使用 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)

输出:

[0, 1, 0, 1, 0, 1, 2, 1, 2]

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

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

为大型数据集使用生成器

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

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

输出:499500

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

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

summary = sum((x for x in range(1000000000)))
print(summary)

输出:

499999999500000000

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

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))

输出:

4940.844053814# get_sum_with_map
3464.1995523349997# get_sum_with_generator

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

总结

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

现在你:

  • リストを作成するためのいくつかの代替方法を学びました。
  • 各方法の利点を確認してください。
  • リスト内包表記へのループと map() 呼び出しを簡素化できます。
  • 分析式に条件付きロジックを追加する方法を理解しました。
  • セットと辞書式を作成できます。
  • 分析式を使用すべきでない場合について学びました。

この記事を最後まで読んでいただきありがとうございます!この投稿が役に立った場合は、コメントを残してください。私の投稿を見逃さないように、忘れずに「フォロー」をクリックしてください。あなたの活動は私の喜びです!幸運を!

以上がPython のリスト内包表記はタスクを解決する効率的な方法ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事は51cto.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。