งูต้นฉบับจับคู่ตุ้มน้ำหนักสองแถวแล้วส่งผลคูณไปสะสมในชามเดียว

Python math.sumprod: คูณเป็นคู่แล้วรวมอย่างอ่านตรงโจทย์

พี่โชว์Engineering

ยอดถ่วงน้ำหนักอย่าง ราคา × จำนวน มักเขียนเป็น 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 กับเครื่องมือที่เหมาะสม