如何在Rust中将扁平记录Vec转换为嵌套结构体数组?
在Rust中手动将扁平记录集合转换为嵌套结构体数组的惯用方式
我有一个扁平的Vec<Record>集合,其中每条记录同时包含预约(Appointment)和服务(Service)的信息——相同a_id的记录属于同一个预约。需要手动将其转换为嵌套的Vec<Appointment>结构,每个Appointment包含预约的基础信息,以及对应的Vec<Service>列表,且不使用任何额外第三方库。
原始扁平记录结构
// 伪代码 use uuid::Uuid; use chrono::NaiveTime; use rust_decimal::Decimal; struct Record { a_id: Uuid, a_working_day_id: Uuid, a_client_id: Uuid, a_start_time: NaiveTime, a_end_time: NaiveTime, s_id: Uuid, s_name: String, s_price: Decimal, s_duration: i32, } let records: Vec<Record> = vec![ // 属于预约#1的记录 Record { /* 字段值 */ }, Record { /* 字段值 */ }, Record { /* 字段值 */ }, // 属于预约#2的记录 Record { /* 字段值 */ }, Record { /* 字段值 */ }, Record { /* 字段值 */ }, // 属于预约#3的记录 Record { /* 字段值 */ }, Record { /* 字段值 */ }, Record { /* 字段值 */ }, ];
目标嵌套结构体定义
// 伪代码 struct Appointment { pub id: Uuid, // 对应Record的a_id pub working_day_id: Uuid, // 对应Record的a_working_day_id pub client_id: Uuid, // 对应Record的a_client_id pub start_time: NaiveTime, // 对应Record的a_start_time pub end_time: NaiveTime, // 对应Record的a_end_time pub services: Vec<Service>, } struct Service { pub id: Uuid, // 对应Record的s_id pub name: String, // 对应Record的s_name pub price: Decimal, // 对应Record的s_price pub duration: i32, // 对应Record的s_duration }
惯用实现方案
核心思路是利用HashMap按预约ID(a_id)分组,遍历每条扁平记录时提取服务信息,合并预约基础信息到对应分组,最后将HashMap的值转换为目标数组。
完整示例代码
use std::collections::HashMap; use uuid::Uuid; use chrono::NaiveTime; use rust_decimal::Decimal; // 原始扁平记录结构 struct Record { a_id: Uuid, a_working_day_id: Uuid, a_client_id: Uuid, a_start_time: NaiveTime, a_end_time: NaiveTime, s_id: Uuid, s_name: String, s_price: Decimal, s_duration: i32, } // 目标嵌套结构体 struct Appointment { pub id: Uuid, pub working_day_id: Uuid, pub client_id: Uuid, pub start_time: NaiveTime, pub end_time: NaiveTime, pub services: Vec<Service>, } struct Service { pub id: Uuid, pub name: String, pub price: Decimal, pub duration: i32, } fn convert_records_to_appointments(records: Vec<Record>) -> Vec<Appointment> { let mut appointment_map: HashMap<Uuid, Appointment> = HashMap::new(); for record in records { // 提取当前记录的服务信息 let service = Service { id: record.s_id, name: record.s_name, price: record.s_price, duration: record.s_duration, }; // 查找或创建对应预约:存在则复用,不存在则初始化新预约 let appointment = appointment_map.entry(record.a_id).or_insert_with(|| Appointment { id: record.a_id, working_day_id: record.a_working_day_id, client_id: record.a_client_id, start_time: record.a_start_time, end_time: record.a_end_time, services: Vec::new(), }); // 将服务添加到预约的服务列表 appointment.services.push(service); } // 将HashMap中的预约转换为Vec返回 appointment_map.into_values().collect() } // 使用示例 fn main() { // 假设此处已初始化好records集合 let records: Vec<Record> = vec![/* ... */]; let appointments = convert_records_to_appointments(records); }
关键说明
- 利用
HashMap::entryAPI高效处理“存在则更新,不存在则插入”的场景,避免重复查找 - 仅需遍历一次原始记录,时间复杂度为O(n)(n为记录总数)
- 默认假设同一预约的所有记录基础信息(
a_working_day_id、a_client_id等)完全一致,若存在信息冲突,可根据需求添加处理逻辑(如保留第一条记录信息、抛出错误等)
内容的提问来源于stack exchange,提问作者Roman Mahotskyi
相关产品推荐
相关产品推荐

