× Giới thiệu Lịch khai giảng Tin tức Sản phẩm học viên

Tính tổng các giá trị theo cách của Python Với sum()

22/03/2023 01:28

Hàm tích hợp sẵn của Python sum()là một cách hiệu quả và Pythonic để tính tổng danh sách các giá trị số. Cùng tìm hiểu cách tính ngay trong bài viết sau

Hàm tích hợp sẵn của Python sum()là một cách hiệu quả và Pythonic để tính tổng danh sách các giá trị số. Cộng nhiều số với nhau là một bước trung gian phổ biến trong nhiều phép tính, do đó đây sum()là một công cụ khá tiện dụng cho một lập trình viên Python.

Là một trường hợp sử dụng bổ sung và thú vị, bạn có thể nối các danh sách và bộ dữ liệu bằng cách sử dụng sum(), điều này có thể thuận tiện khi bạn cần làm phẳng một danh sách các danh sách.

Tìm hiểu vấn đề tổng kết

Tính tổng các giá trị số với nhau là một vấn đề khá phổ biến trong lập trình. Ví dụ: giả sử bạn có một danh sách các số [1, 2, 3, 4, 5] và muốn cộng chúng lại với nhau để tính tổng của chúng. Với số học tiêu chuẩn, bạn sẽ làm một cái gì đó như thế này:

1 + 2 + 3 + 4 + 5 = 15

Theo như toán học, biểu thức này khá đơn giản. Nó hướng dẫn bạn qua một loạt các phép cộng ngắn cho đến khi bạn tìm được tổng của tất cả các số.

Có thể thực hiện phép tính cụ thể này bằng tay, nhưng hãy tưởng tượng một số tình huống khác mà điều đó có thể không khả thi. Nếu bạn có một danh sách số đặc biệt dài, việc thêm bằng tay có thể không hiệu quả và dễ bị lỗi. Điều gì xảy ra nếu bạn thậm chí không biết có bao nhiêu mục trong danh sách? Cuối cùng, hãy tưởng tượng một kịch bản trong đó số lượng mục bạn cần thêm thay đổi linh hoạt hoặc không thể đoán trước.

Trong những tình huống như thế này, cho dù bạn có một danh sách số dài hay ngắn , Python có thể khá hữu ích để giải các bài toán tính tổng .

Nếu bạn muốn tính tổng các số bằng cách tạo giải pháp của riêng mình từ đầu, thì bạn có thể thử sử dụng vòng forlặp :

>>>
>>> numbers = [1, 2, 3, 4, 5]
>>> total = 0

>>> for number in numbers:
...     total += number
...

>>> total
15

Tại đây, trước tiên bạn tạo totalvà khởi tạo nó thành 0Biến này hoạt động như một bộ tích lũy trong đó bạn lưu trữ các kết quả trung gian cho đến khi bạn nhận được kết quả cuối cùng. Vòng lặp lặp đi lặp lại numbersvà cập nhật totalbằng cách tích lũy từng giá trị liên tiếp bằng cách sử dụng phép gán tăng cường .

Bạn cũng có thể bọc forvòng lặp trong một hàm . Bằng cách này, bạn có thể sử dụng lại mã cho các danh sách khác nhau:

>>>
>>> def sum_numbers(numbers):
...     total = 0
...     for number in numbers:
...         total += number
...     return total
...

>>> sum_numbers([1, 2, 3, 4, 5])
15

>>> sum_numbers([])
0

Trong sum_numbers(), bạn lấy một đối số có thể lặp lại — cụ thể là danh sách các giá trị số — làm đối số và trả về tổng giá trị trong danh sách đầu vào. Nếu danh sách đầu vào trống, thì hàm trả về 0. Vòng forlặp giống như vòng lặp mà bạn đã thấy trước đây.

Bạn cũng có thể sử dụng đệ quy thay vì lặp lại. Đệ quy là một kỹ thuật lập trình chức năng trong đó một hàm được gọi theo định nghĩa của chính nó. Nói cách khác, một hàm đệ quy gọi chính nó trong một vòng lặp:

>>>
>>> def sum_numbers(numbers):
...     if len(numbers) == 0:
...         return 0
...     return numbers[0] + sum_numbers(numbers[1:])
...

>>> sum_numbers([1, 2, 3, 4, 5])
15

Khi bạn định nghĩa một hàm đệ quy, bạn có nguy cơ chạy vào một vòng lặp vô hạn. Để ngăn chặn điều này, bạn cần xác định cả trường hợp cơ sở dừng đệ quy và trường hợp đệ quy để gọi hàm và bắt đầu vòng lặp ẩn.

Trong ví dụ trên, trường hợp cơ sở ngụ ý rằng tổng của danh sách có độ dài bằng 0 là 0. Trường hợp đệ quy ngụ ý rằng tổng số tiền là giá trị đầu tiên, numbers[0], cộng với tổng của các giá trị còn lại, numbers[1:]. Bởi vì trường hợp đệ quy sử dụng một chuỗi ngắn hơn trên mỗi lần lặp lại, bạn sẽ gặp trường hợp cơ sở khi numbersdanh sách có độ dài bằng không. Kết quả cuối cùng, bạn nhận được tổng của tất cả các mục trong danh sách đầu vào của mình, numbers.

Một tùy chọn khác để tính tổng danh sách các số trong Python là sử dụng reduce()from functools. Để lấy tổng của một danh sách các số, bạn có thể chuyển một trong hai operator.addhoặc một lambdahàm thích hợp làm đối số đầu tiên cho reduce():

>>>
>>> from functools import reduce
>>> from operator import add

>>> reduce(add, [1, 2, 3, 4, 5])
15

>>> reduce(add, [])
Traceback (most recent call last):
    ...
TypeError: reduce() of empty sequence with no initial value

>>> reduce(lambda x, y: x + y, [1, 2, 3, 4, 5])
15

Bạn có thể gọi reduce()với một rút gọn hoặc gấp , functioncùng với một iterableas đối số. Sau đó, reduce()sử dụng hàm đầu vào để xử lý iterablevà trả về một giá trị tích lũy duy nhất.

Trong ví dụ đầu tiên, hàm rút gọn là add(), lấy hai số và cộng chúng lại với nhau. Kết quả cuối cùng là tổng của các số trong đầu vào iterable. Như một nhược điểm, reduce()tăng a TypeErrorkhi bạn gọi nó bằng một số trống iterable.

Trong ví dụ thứ hai, hàm rút gọn là một lambdahàm trả về phép cộng hai số.

Vì các phép tính tổng như thế này là phổ biến trong lập trình nên viết mã một hàm mới mỗi khi bạn cần tính tổng một số số là công việc lặp đi lặp lại nhiều lần. Ngoài ra, sử dụng reduce()không phải là giải pháp dễ đọc nhất dành cho bạn.

Python cung cấp một hàm dựng sẵn chuyên dụng để giải quyết vấn đề này. Chức năng này được gọi một cách thuận tiện sum(). Vì đây là một chức năng tích hợp sẵn nên bạn có thể sử dụng nó trực tiếp trong mã của mình mà không cần nhập bất kỳ thứ gì.

 

Bắt đầu với Pythonsum()

Khả năng đọc là một trong những nguyên tắc quan trọng nhất đằng sau triết lý của Python . Hình dung những gì bạn đang yêu cầu một vòng lặp thực hiện khi tính tổng một danh sách các giá trị. Bạn muốn nó lặp qua một số số, tích chúng trong một biến trung gian và trả về tổng cuối cùng. Tuy nhiên, bạn có thể tưởng tượng ra một phiên bản tổng kết dễ đọc hơn mà không cần vòng lặp. Bạn muốn Python lấy một số số và tính tổng chúng lại với nhau.

Bây giờ hãy nghĩ về cách reduce()thực hiện tổng kết. Việc sử dụng reduce()được cho là ít dễ đọc hơn và ít đơn giản hơn so với giải pháp dựa trên vòng lặp.

Đây là lý do tại sao Python 2.3 được thêm vào sum()dưới dạng hàm tích hợp để cung cấp giải pháp Pythonic cho bài toán tổng kết. Alex Martelli đã đóng góp hàm này, mà ngày nay là cú pháp ưa thích để tính tổng một danh sách các giá trị:

>>>
>>> sum([1, 2, 3, 4, 5])
15

>>> sum([])
0

Ồ! Đó là gọn gàng, phải không? Nó đọc như tiếng Anh thuần túy và truyền đạt rõ ràng hành động bạn đang thực hiện trên danh sách đầu vào. Cách sử dụng sum()dễ đọc hơn forvòng lặp hoặc reduce()cuộc gọi. Không giống như reduce()sum()không tăng a TypeErrorkhi bạn cung cấp một lần lặp trống. Thay vào đó, nó trả về một cách dễ hiểu 0.

Bạn có thể gọi sum()với hai đối số sau:

  1. iterablelà một đối số bắt buộc có thể chứa bất kỳ Python iterable nào. Iterable thường chứa các giá trị số nhưng cũng có thể chứa các danh sách hoặc bộ dữ liệu .
  2. startlà một đối số tùy chọn có thể giữ giá trị ban đầu. Giá trị này sau đó được thêm vào kết quả cuối cùng. Nó mặc định là 0.

Bên trong, sum()thêm startcộng các giá trị iterabletừ trái sang phải. Các giá trị trong đầu vào iterablethường là các số, nhưng bạn cũng có thể sử dụng các danh sách và bộ dữ liệu. Đối số tùy chọn startcó thể chấp nhận một số, danh sách hoặc bộ, tùy thuộc vào nội dung được truyền cho iterable. Nó không thể lấy một chuỗi .

Trong hai phần sau, bạn sẽ tìm hiểu những kiến ​​thức cơ bản về cách sử dụng sum()trong mã của mình.

Đối số bắt buộc:iterable

Việc chấp nhận bất kỳ Python nào có thể lặp lại làm đối số đầu tiên của nó sẽ tạo ra các tệp sum()chung, có thể tái sử dụng và đa hình . Do tính năng này, bạn có thể sử dụng sum()với danh sách, bộ dữ liệu, bộ , rangeđối tượng và từ điển :

>>>
>>> # Use a list
>>> sum([1, 2, 3, 4, 5])
15

>>> # Use a tuple
>>> sum((1, 2, 3, 4, 5))
15

>>> # Use a set
>>> sum({1, 2, 3, 4, 5})
15

>>> # Use a range
>>> sum(range(1, 6))
15

>>> # Use a dictionary
>>> sum({1: "one", 2: "two", 3: "three"})
6
>>> sum({1: "one", 2: "two", 3: "three"}.keys())
6

Trong tất cả các ví dụ này, sum()tính toán tổng cộng của tất cả các giá trị trong đầu vào có thể lặp lại bất kể loại của chúng. Trong hai ví dụ về từ điển, cả hai lệnh gọi sum()trả về tổng các khóa của từ điển đầu vào. Ví dụ đầu tiên tính tổng các khóa theo mặc định và ví dụ thứ hai tính tổng các khóa do lệnh .keys()gọi trên từ điển đầu vào.

Nếu từ điển của bạn lưu trữ các số trong các giá trị của nó và bạn muốn tính tổng các giá trị này thay vì các khóa, thì bạn có thể thực hiện việc này bằng cách sử dụng .values()giống như trong .keys()ví dụ.

Bạn cũng có thể sử dụng sum()với khả năng hiểu danh sách làm đối số. Đây là một ví dụ tính tổng bình phương của một dải giá trị:

>>>
>>> sum([x ** 2 for x in range(1, 6)])
55

Python 2.4 đã thêm các biểu thức trình tạo vào ngôn ngữ. Một lần nữa, sum()hoạt động như mong đợi khi bạn sử dụng biểu thức trình tạo làm đối số:

>>>
>>> sum(x ** 2 for x in range(1, 6))
55

Ví dụ này cho thấy một trong những kỹ thuật Pythonic nhất để tiếp cận vấn đề tổng kết. Nó cung cấp một giải pháp tinh tế, dễ đọc và hiệu quả trong một dòng mã.

Đối số tùy chọn:start

Đối số thứ hai và tùy chọn, start, cho phép bạn cung cấp một giá trị để khởi tạo quy trình tổng kết. Đối số này rất hữu ích khi bạn cần xử lý tuần tự các giá trị tích lũy:

>>>
>>> sum([1, 2, 3, 4, 5], 100)  # Positional argument
115

>>> sum([1, 2, 3, 4, 5], start=100)  # Keyword argument
115

Tại đây, bạn cung cấp giá trị ban đầu 100là start. Hiệu ứng ròng là sum()thêm giá trị này vào tổng tích lũy của các giá trị trong lần lặp đầu vào. Lưu ý rằng bạn có thể cung cấp startdưới dạng đối số vị trí hoặc đối số từ khóa . Tùy chọn thứ hai rõ ràng hơn và dễ đọc hơn.

Nếu bạn không cung cấp giá trị cho start, thì giá trị đó sẽ mặc định là 0. Giá trị mặc định 0đảm bảo hành vi dự kiến ​​trả về tổng của các giá trị đầu vào.

Tổng các giá trị số

Mục đích chính của sum()là cung cấp một cách Pythonic để cộng các giá trị số lại với nhau. Đến đây, bạn đã biết cách sử dụng hàm tính tổng các số nguyên. Ngoài ra, bạn có thể sử dụng sum()với bất kỳ loại Python số nào khác, chẳng hạn như floatcomplexdecimal.Decimalvà fractions.Fraction.

Dưới đây là một số ví dụ về cách sử dụng sum()với các giá trị thuộc các loại số khác nhau:

>>>
>>> from decimal import Decimal
>>> from fractions import Fraction

>>> # Sum floating-point numbers
>>> sum([10.2, 12.5, 11.8])
34.5
>>> sum([10.2, 12.5, 11.8, float("inf")])
inf
>>> sum([10.2, 12.5, 11.8, float("nan")])
nan

>>> # Sum complex numbers
>>> sum([3 + 2j, 5 + 6j])
(8+8j)

>>> # Sum Decimal numbers
>>> sum([Decimal("10.2"), Decimal("12.5"), Decimal("11.8")])
Decimal('34.5')

>>> # Sum Fraction numbers
>>> sum([Fraction(51, 5), Fraction(25, 2), Fraction(59, 5)])
Fraction(69, 2)

Ở đây, lần đầu tiên bạn sử dụng sum()với số dấu phẩy động . Cần lưu ý hành vi của hàm khi bạn sử dụng các ký hiệu đặc biệt infvà nantrong các cuộc gọi float("inf")và float("nan"). Biểu tượng đầu tiên đại diện cho một giá trị vô hạn , vì vậy sum()trả về inf. Biểu tượng thứ hai đại diện cho các giá trị NaN (không phải số) . Vì bạn không thể cộng các số với các số không phải là số, nên nankết quả là bạn nhận được.

Các ví dụ khác tính tổng các lần lặp của complexDecimalvà Fractionsố. Trong mọi trường hợp, sum()trả về tổng tích lũy kết quả bằng cách sử dụng loại số thích hợp.

trình tự nối

Mặc dù sum()chủ yếu nhằm mục đích hoạt động trên các giá trị số, nhưng bạn cũng có thể sử dụng hàm này để nối các chuỗi chẳng hạn như danh sách và bộ dữ liệu. Để làm điều đó, bạn cần cung cấp một giá trị thích hợp cho start:

>>>
>>> num_lists = [[1, 2, 3], [4, 5, 6]]
>>> sum(num_lists, start=[])
[1, 2, 3, 4, 5, 6]

>>> # Equivalent concatenation
>>> [1, 2, 3] + [4, 5, 6]
[1, 2, 3, 4, 5, 6]

>>> num_tuples = ((1, 2, 3), (4, 5, 6))
>>> sum(num_tuples, start=())
(1, 2, 3, 4, 5, 6)

>>> # Equivalent concatenation
>>> (1, 2, 3) + (4, 5, 6)
(1, 2, 3, 4, 5, 6)

Trong các ví dụ này, bạn sử dụng sum()để nối các danh sách và bộ dữ liệu. Đây là một tính năng thú vị mà bạn có thể sử dụng để làm phẳng danh sách các danh sách hoặc một bộ gồm các bộ. Yêu cầu chính để các ví dụ này hoạt động là chọn một giá trị thích hợp cho start. Ví dụ: nếu bạn muốn nối các danh sách, thì startcần giữ một danh sách.

Trong các ví dụ trên, sum()đang thực hiện thao tác nối bên trong, do đó, thao tác này chỉ hoạt động với các loại trình tự hỗ trợ nối, ngoại trừ các chuỗi:

>>>
>>> num_strs = ["123", "456"]
>>> sum(num_strs, "0")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: sum() can't sum strings [use ''.join(seq) instead]

Khi bạn cố gắng sử dụng sum()để nối các chuỗi, bạn sẽ nhận được tệp TypeError. Như thông báo ngoại lệ gợi ý, bạn nên sử dụng str.join()để nối các chuỗi trong Python. Bạn sẽ thấy các ví dụ về cách sử dụng phương pháp này sau này khi đến phần Sử dụng các phương pháp thay thế chosum() .

Thực hành với Pythonsum()

Cho đến giờ, bạn đã học được những điều cơ bản khi làm việc với sum(). Bạn đã học cách sử dụng hàm này để cộng các giá trị số với nhau và cũng để nối các chuỗi như danh sách và bộ.

Trong phần này, bạn sẽ xem xét thêm một số ví dụ về thời điểm và cách sử dụng sum()trong mã của mình. Với những ví dụ thực tế này, bạn sẽ biết rằng hàm tích hợp sẵn này khá hữu ích khi bạn đang thực hiện các phép tính yêu cầu tìm tổng của một chuỗi số như một bước trung gian.

Bạn cũng sẽ biết rằng điều đó sum()có thể hữu ích khi bạn làm việc với các danh sách và bộ dữ liệu. Một ví dụ đặc biệt mà bạn sẽ xem xét là khi bạn cần làm phẳng một danh sách các danh sách.

Tính toán các khoản tiền tích lũy

Ví dụ đầu tiên bạn sẽ viết mã liên quan đến cách tận dụng startđối số để tính tổng các danh sách giá trị số tích lũy.

Giả sử bạn đang phát triển một hệ thống để quản lý việc bán một sản phẩm nhất định tại một số điểm bán hàng khác nhau. Hàng ngày, bạn nhận được báo cáo đơn vị bán hàng từ mỗi điểm bán hàng. Bạn cần tính tổng cộng dồn một cách có hệ thống để biết cả công ty đã bán được bao nhiêu đơn vị trong tuần. Để giải quyết vấn đề này, bạn có thể sử dụng sum():

>>>
>>> cumulative_sales = 0

>>> monday = [50, 27, 42]
>>> cumulative_sales = sum(monday, start=cumulative_sales)
>>> cumulative_sales
119

>>> tuesday = [12, 32, 15]
>>> cumulative_sales = sum(tuesday, start=cumulative_sales)
>>> cumulative_sales
178

>>> wednesday = [20, 24, 42]
>>> cumulative_sales = sum(wednesday, start=cumulative_sales)
>>> cumulative_sales
264
    ...

Bằng cách sử dụng start, bạn đặt một giá trị ban đầu để khởi tạo tổng, cho phép bạn thêm các đơn vị liên tiếp vào tổng phụ đã tính toán trước đó. Vào cuối tuần, bạn sẽ có tổng số đơn vị đã bán của công ty.

Tính giá trị trung bình của một mẫu

Một trường hợp sử dụng thực tế khác sum()là sử dụng nó như một phép tính trung gian trước khi thực hiện các phép tính tiếp theo. Ví dụ: giả sử bạn cần tính giá trị trung bình cộng của một mẫu giá trị số. Giá trị trung bình số học, còn được gọi là giá trị trung bình , là tổng của các giá trị chia cho số lượng giá trị hoặc điểm dữ liệu trong mẫu.

Nếu bạn có mẫu [2, 3, 4, 2, 3, 6, 4, 2] và bạn muốn tính trung bình cộng bằng tay, thì bạn có thể giải phép toán này:

(2 + 3 + 4 + 2 + 3 + 6 + 4 + 2)/8 = 3,25

Nếu bạn muốn tăng tốc độ này bằng cách sử dụng Python, bạn có thể chia nó thành hai phần. Phần đầu tiên của phép tính này, nơi bạn cộng các số lại với nhau, là một nhiệm vụ cho sum(). Phần tiếp theo của phép toán, nơi bạn chia cho 8, sử dụng số đếm trong mẫu của bạn. Để tính toán ước số của bạn , bạn có thể sử dụng len():

>>>
>>> data_points = [2, 3, 4, 2, 3, 6, 4, 2]

>>> sum(data_points) / len(data_points)
3.25

Tại đây, lệnh gọi để sum()tính tổng các điểm dữ liệu trong mẫu của bạn. Tiếp theo, bạn sử dụng len()để lấy số điểm dữ liệu. Cuối cùng, bạn thực hiện phép chia cần thiết để tính trung bình cộng của mẫu.

Trong thực tế, bạn có thể muốn biến mã này thành một hàm với một số tính năng bổ sung, chẳng hạn như tên mô tả và kiểm tra các mẫu trống:

>>>
>>> # Python >= 3.8

>>> def average(data_points):
...     if (num_points := len(data_points)) == 0:
...         raise ValueError("average requires at least one data point")
...     return sum(data_points) / num_points
...

>>> average([2, 3, 4, 2, 3, 6, 4, 2])
3.25

>>> average([])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in average
ValueError: average requires at least one data point

Bên trong average(), trước tiên bạn kiểm tra xem mẫu đầu vào có bất kỳ điểm dữ liệu nào không. Nếu không, thì bạn đưa ra một ValueErrorthông điệp mô tả. Trong ví dụ này, bạn sử dụng toán tử hải mã để lưu trữ số lượng điểm dữ liệu trong biến num_pointsđể bạn không cần gọi len()lại. Câu lệnh return tính giá trị trung bình số học của mẫu và gửi nó trở lại mã gọi.