Python Counter.total: รวมจำนวนคงเหลือโดยยังเห็นค่าติดลบ
Counter ไม่ได้เก็บเฉพาะจำนวนบวก มันรองรับศูนย์และค่าติดลบสำหรับการคืนของหรือปรับยอดด้วย Counter.total() รวม count ทุก key ตามที่เก็บอยู่ จึงเหมาะกับยอดสุทธิ แต่ต้องเข้าใจว่าไม่ได้ตัดค่าติดลบทิ้งครับ
WHY: รวมสมุดรับเข้าและคืนของเล่มเดียว
ร้านหนึ่งมีรับของ 12 ชิ้นและคืนผู้ขาย 2 ชิ้น ยอดสุทธิคือ 10 ไม่ใช่ 12 การใช้ sum(counter.values()) ได้คำตอบเดียวกัน แต่ total() สื่อเจตนาว่าเรากำลังรวม counter และอ่านง่ายกว่าใน code review
from collections import Counter
import unittest
def net_units(events: list[tuple[str, int]]) -> int:
counts: Counter[str] = Counter()
for sku, delta in events:
counts[sku] += delta
return counts.total()
class CounterTotalTests(unittest.TestCase):
def test_includes_negative_adjustments(self) -> None:
events = [("tea", 12), ("tea", -2), ("coffee", 5)]
self.assertEqual(net_units(events), 15)
def test_empty_counter_is_zero(self) -> None:
self.assertEqual(net_units([]), 0)
def test_zero_and_negative_keys_still_contribute(self) -> None:
counts = Counter({"ready": 3, "held": -1, "empty": 0})
self.assertEqual(counts.total(), 2)
if __name__ == "__main__":
unittest.main()
HOW: total ไม่ได้บอกว่า inventory ถูกต้อง
ยอดรวมเป็นศูนย์อาจเกิดจากทุกอย่างหมดพอดี หรือมีสินค้า 100 ชิ้นหักลบกับ debt 100 ชิ้น การตัดสิน reorder จึงต้องดูราย key ไม่ใช่ total อย่างเดียว ถ้าค่าติดลบผิดกฎธุรกิจ ให้ validate หลังอัปเดตแต่ละ event และหยุด transaction ก่อน commit
Unary plus เช่น +counts สร้าง Counter ใหม่ที่เก็บเฉพาะ count บวก เหมาะกับรายการคงเหลือที่พร้อมใช้ แต่จะเปลี่ยนความหมายของ total() เพราะรายการติดลบและศูนย์ถูกตัดออก ต้องตั้งชื่อขั้น normalize ให้ชัดและอย่าใช้ก่อน audit adjustment
Recap
- ใช้
total()เมื่ออยากได้ผลรวมสุทธิของ count ทั้งหมด - จำว่าศูนย์และค่าติดลบยังอยู่ใน Counter
- ดูราย key สำหรับ invariant และ reorder decision
- เก็บ event/audit trail ก่อน normalize ด้วย unary plus
- ทดสอบ empty, negative adjustment และยอดหักล้างกัน