Rust Iterator::is_sorted_by_key: ตรวจลำดับโดยไม่สร้าง Vec สำรอง
บางระบบต้องปฏิเสธ event ที่ priority ถอยหลัง แต่ไม่จำเป็นต้อง sort หรือสร้าง collection ใหม่ Iterator::is_sorted_by_key เดินสมาชิกตามลำดับเดิมและหยุดเมื่อพบคู่ที่ผิดกติกา จึงเหมาะกับ validation ก่อนรับ batch ครับ
WHY: ตรวจตั๋วบนสายพาน ไม่ต้องยกลงมาเรียงใหม่
ถ้าของมาถูกลำดับอยู่แล้ว เราเพียงมองกล่องติดกันบนสายพาน การ collect แล้ว sort เหมือนยกทุกกล่องลงโกดัง ทั้งใช้หน่วยความจำเพิ่มและทำลายหลักฐานว่าต้นทางส่งผิดลำดับหรือไม่
#[derive(Debug)]
struct Job { priority: u8, name: &'static str }
fn priorities_are_ordered(jobs: &[Job]) -> bool {
jobs.iter().is_sorted_by_key(|job| job.priority)
}
#[test]
fn validates_original_order() {
let ok = [
Job { priority: 1, name: "thumbnail" },
Job { priority: 1, name: "metadata" },
Job { priority: 3, name: "publish" },
];
assert!(priorities_are_ordered(&ok));
assert_eq!(ok[0].name, "thumbnail");
let reversed = [
Job { priority: 2, name: "publish" },
Job { priority: 1, name: "validate" },
];
assert!(!priorities_are_ordered(&reversed));
assert!(priorities_are_ordered(&[]));
}
HOW: key ต้องสะท้อนลำดับธุรกิจจริง
ฟังก์ชันถือค่าซ้ำว่าเรียงถูก เพราะตรวจแบบไม่ลดลง ถ้าธุรกิจต้องการเพิ่มขึ้นอย่างเคร่งครัด ให้ใช้ is_sorted_by พร้อม comparator ที่ปฏิเสธค่าซ้ำ หรือวนคู่ติดกันเองเพื่อคืนตำแหน่ง error ที่ละเอียดกว่า
Closure ถูกเรียกเพื่อสร้าง key ระหว่างเดิน iterator จึงควรราคาถูกและไม่มี side effect ถ้า key เป็น String ที่ต้อง allocate ทุกครั้ง อาจ normalize ก่อน หรือเทียบ reference ด้วย is_sorted_by แทน นอกจากนี้ iterator ถูก consume หลังตรวจ ถ้าต้องใช้ข้อมูลต่อให้ยืมผ่าน .iter() เหมือนตัวอย่าง หรือออกแบบ pipeline ให้ validation เป็นขั้นเดียวกับการประมวลผล
Recap
- ใช้
is_sorted_by_keyเพื่อตรวจลำดับเดิม ไม่ใช่จัดเรียงข้อมูล - ตกลงก่อนว่าค่าซ้ำยอมรับได้หรือไม่
- ให้ key extraction ราคาถูกและ deterministic
- จำไว้ว่า iterator ถูก consume
- ถ้าต้องบอก index ที่ผิด ให้เขียน validation ที่เก็บตำแหน่งเพิ่ม