Python math.sumprod: คูณเป็นคู่แล้วรวมอย่างอ่านตรงโจทย์
ยอดถ่วงน้ำหนักอย่าง ราคา × จำนวน มักเขียนเป็น sum(a * b for a, b in zip(...)) แต่ zip แบบปกติหยุดตาม input ที่สั้นกว่าเงียบ ๆ ครับ math.sumprod สื่อว่า “คูณเป็นคู่แล้วรวม” ตรงโจทย์และกำหนดให้ input ยาวเท่ากัน
WHY: contract ความยาวสำคัญกว่าความสั้น
ถ้ารายการราคามีสามชิ้นแต่จำนวนมีสองชิ้น การตัดชิ้นสุดท้ายทิ้งเงียบ ๆ เหมือนแคชเชียร์ไม่คิดของท้ายตะกร้า ผลรวมดูสมเหตุผลแต่ผิด sumprod ทำให้ mismatch เป็น error ซึ่งเหมาะกับ boundary ทางธุรกิจ
import math
import unittest
def invoice_total(prices, quantities):
return math.sumprod(prices, quantities)
class SumProdTests(unittest.TestCase):
def test_weighted_total(self):
self.assertEqual(invoice_total([10, 25, 7], [2, 1, 3]), 66)
def test_lengths_must_match(self):
with self.assertRaises(ValueError):
invoice_total([10, 25], [2])
def test_float_result(self):
self.assertAlmostEqual(invoice_total([0.1, 0.2], [3, 4]), 1.1)
if __name__ == "__main__":
unittest.main()
ฟังก์ชันนี้เหมาะกับ dot product, คะแนนถ่วงน้ำหนัก และยอดสินค้า แต่เงินที่ต้องการกฎทศนิยมชัดควรใช้ Decimal ตั้งแต่ input อย่าแปลงจาก float ทีหลัง เพราะความคลาดเคลื่อนเกิดไปแล้ว และถ้าต้องการ vectorized array ขนาดใหญ่มาก library เฉพาะทางอาจเร็วกว่า stdlib
Recap
- ใช้
sumprodเมื่อโจทย์คือคูณสมาชิกเป็นคู่แล้วรวม - ความยาวไม่เท่ากันจะไม่ถูกตัดเงียบ ๆ
- เงินควรใช้
Decimalตาม policy ของระบบ - งาน array ใหญ่ควร benchmark กับเครื่องมือที่เหมาะสม