use std::collections::HashMap;
#[derive(Debug, Clone)]
pub struct TreeNode<T> {
pub data: T, pub children: Vec<TreeNode<T>>, pub children_count: usize, }
pub struct TreeUtil;
impl TreeUtil {
pub fn to_trees<T: TreeData + Clone>(vec: Vec<T>) -> Vec<TreeNode<T>> {
let mut node_map: HashMap<T::Id, TreeNode<T>> = vec
.into_iter()
.map(|data| {
(
data.id(),
TreeNode {
data: data.clone(),
children: Vec::new(),
children_count: 0, },
)
})
.collect();
let mut root_ids = Vec::new();
for (id, node) in node_map.clone() {
let pid = node.data.pid();
if pid == T::root_pid() {
root_ids.push(id);
} else {
if let Some(parent) = node_map.get_mut(&pid) {
parent.children.push(node);
}
}
}
for root_id in &root_ids {
if let Some(root_node) = node_map.get_mut(root_id) {
Self::calculate_children_count(root_node);
}
}
root_ids
.into_iter()
.filter_map(|id| node_map.remove(&id))
.collect()
}
fn calculate_children_count<T: TreeData>(node: &mut TreeNode<T>) -> usize {
let mut total = node.children.len();
for child in &mut node.children {
total += Self::calculate_children_count(child);
}
node.children_count = total;
total }
}
pub trait TreeData {
type Id: std::hash::Hash + Eq + Clone;
fn id(&self) -> Self::Id; fn name(&self) -> &str; fn pid(&self) -> Self::Id; fn root_pid() -> Self::Id; }
#[derive(Debug, Clone)]
struct Menu {
id: u64,
name: String,
pid: u64,
}
impl TreeData for Menu {
type Id = u64;
fn id(&self) -> Self::Id { self.id }
fn name(&self) -> &str { &self.name }
fn pid(&self) -> Self::Id { self.pid }
fn root_pid() -> Self::Id { 0 }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test01() {
let menus = vec![
Menu {
id: 1,
name: "系统管理".to_string(),
pid: 0,
},
Menu {
id: 2,
name: "用户管理".to_string(),
pid: 1,
},
Menu {
id: 3,
name: "角色管理".to_string(),
pid: 1,
},
Menu {
id: 4,
name: "菜单管理".to_string(),
pid: 2,
},
Menu {
id: 5,
name: "数据统计".to_string(),
pid: 0,
},
];
let trees = TreeUtil::to_trees(menus);
println!("{:#?}", trees);
}
}