บทนำ
เมื่อมีลิสต์ผสมประเภทข้อมูล (mixed types) ต้องการจับกลุ่มเฉพาะสตริงที่ติดต่อกัน (contiguous strings) ให้เป็นสับรายการ แล้วคืนลิสต์ที่ผสมระหว่างค่าเดี่ยวและสับรายการสตริง
ตัวอย่างโค้ด
from itertools import groupby
def is_string(elem):
"""ตรวจสอบว่าเป็นสตริงหรือไม่"""
return isinstance(elem, str)
def group_contiguous_strings(lst):
"""จับกลุ่มสตริงติดต่อกัน yield ผลลัพธ์"""
for is_str, group in groupby(lst, key=is_string):
if is_str:
yield list(group) # สตริงติดต่อกัน → สับรายการ
else:
yield from group # ไม่ใช่สตริง → yield ตัวเดี่ยว
# ทดสอบ
my_list = [52, 11, 'py', 'th', 'on', 11, 52, 'i', 's', 18, 'f', 'un', 99]
print("ลิสต์ต้นทาง:", my_list)
result = [*group_contiguous_strings(my_list)]
print("ผลลัพธ์:", result)
ผลลัพธ์
ลิสต์ต้นทาง: [52, 11, 'py', 'th', 'on', 11, 52, 'i', 's', 18, 'f', 'un', 99]
ผลลัพธ์: [52, 11, ['py', 'th', 'on'], 11, 52, ['i', 's'], 18, ['f', 'un'], 99]
คำอธิบายการทำงาน
groupby(lst, key=is_string)แบ่งลิสต์เป็นกลุ่มที่ key (True/False) ติดต่อกัน- ถ้า
is_str == True: รวมกลุ่มเป็น list แล้ว yield - ถ้า
is_str == False: ใช้yield fromyield แต่ละตัวแยกกัน
การประยุกต์: รวมสตริงในกลุ่ม
def group_and_join_strings(lst, separator=''):
"""จับกลุ่มสตริงติดต่อกันและ join รวม"""
result = []
for is_str, group in groupby(lst, key=is_string):
if is_str:
result.append(separator.join(group))
else:
result.extend(group)
return result
print(group_and_join_strings(my_list))
# [52, 11, 'python', 11, 52, 'is', 18, 'fun', 99]
print(group_and_join_strings(my_list, ' '))
# [52, 11, 'py th on', 11, 52, 'i s', 18, 'f un', 99]
กรณีใช้งานจริง
- Parse log lines: จับกลุ่มข้อความ error ติดต่อกัน
- NLP: รวม tokens ที่เป็นคำต่อเนื่อง
- Data cleaning: รวม string fragments ที่แยกกันเก็บ
ข้อควรระวัง
groupbyต้องการข้อมูลที่ "ติดต่อกัน" แล้ว - ไม่ได้จัดกลุ่มค่าที่ไม่ติดกันyield fromใช้ได้ใน Python 3.3+- ฟังก์ชัน key ควรคืนค่าที่ hashable และ consistent
สรุป
ใช้ itertools.groupby ร่วมกับ yield/yield from จับกลุ่มสตริงติดต่อกันได้อย่างมีประสิทธิภาพ โครงสร้างผลลัพธ์คงเหลือค่า non-string เป็นตัวเดี่ยว สตริงติดต่อกันกลายเป็นสับรายการ