It's a tree
This commit is contained in:
commit
629075f94d
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/target
|
||||
Cargo.lock
|
8
Cargo.toml
Normal file
8
Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "a-tree"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
63
examples/generate.rs
Normal file
63
examples/generate.rs
Normal file
|
@ -0,0 +1,63 @@
|
|||
use a_tree::Tree;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
enum Direction {
|
||||
Up,
|
||||
Down,
|
||||
Left,
|
||||
Right,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct Coordinates {
|
||||
x: usize,
|
||||
y: usize,
|
||||
}
|
||||
|
||||
const ALL_DIRECTIONS: [Direction; 4] = [
|
||||
Direction::Up,
|
||||
Direction::Down,
|
||||
Direction::Left,
|
||||
Direction::Right,
|
||||
];
|
||||
|
||||
fn next_level(value: &Coordinates) -> Vec<(Direction, Coordinates)> {
|
||||
ALL_DIRECTIONS
|
||||
.into_iter()
|
||||
.filter_map(|direction| {
|
||||
let new_coords = match direction {
|
||||
Direction::Up => Coordinates {
|
||||
x: value.x,
|
||||
y: value.y + 1,
|
||||
},
|
||||
Direction::Right => Coordinates {
|
||||
x: value.x + 1,
|
||||
y: value.y,
|
||||
},
|
||||
Direction::Down if value.y > 0 => Coordinates {
|
||||
x: value.x,
|
||||
y: value.y - 1,
|
||||
},
|
||||
Direction::Left if value.x > 0 => Coordinates {
|
||||
x: value.x - 1,
|
||||
y: value.y,
|
||||
},
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
Some((direction, new_coords))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut tree = Tree::generations(Coordinates::default(), 3, next_level);
|
||||
|
||||
println!("{:#?}", tree);
|
||||
println!("{:?}", tree.leaves());
|
||||
|
||||
tree.retain(|item| item.x > 0 && item.y > 0);
|
||||
|
||||
println!("{:#?}", tree);
|
||||
println!("{:?}", tree.leaves());
|
||||
}
|
82
src/lib.rs
Normal file
82
src/lib.rs
Normal file
|
@ -0,0 +1,82 @@
|
|||
use std::collections::HashMap;
|
||||
use std::hash::Hash;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Tree<K, T> {
|
||||
value: T,
|
||||
children: HashMap<K, Tree<K, T>>,
|
||||
}
|
||||
|
||||
impl<K, T> Tree<K, T>
|
||||
where
|
||||
K: Eq + Hash,
|
||||
{
|
||||
pub fn new(item: T) -> Self {
|
||||
Tree {
|
||||
value: item,
|
||||
children: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generations<F>(start: T, depth: usize, callback: F) -> Self
|
||||
where
|
||||
F: Fn(&T) -> Vec<(K, T)> + Copy,
|
||||
{
|
||||
let mut children = HashMap::new();
|
||||
|
||||
if depth != 0 {
|
||||
for (key, value) in (callback)(&start) {
|
||||
let child = Self::generations(value, depth - 1, callback);
|
||||
children.insert(key, child);
|
||||
}
|
||||
}
|
||||
|
||||
Tree {
|
||||
value: start,
|
||||
children,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn leaves(&self) -> Vec<(Vec<&K>, &T)> {
|
||||
self.do_leaves(vec![])
|
||||
}
|
||||
|
||||
fn do_leaves<'a>(&'a self, path: Vec<&'a K>) -> Vec<(Vec<&'a K>, &'a T)> {
|
||||
if self.children.is_empty() {
|
||||
vec![(path, &self.value)]
|
||||
} else {
|
||||
self.children
|
||||
.iter()
|
||||
.flat_map(|(key, child)| {
|
||||
let mut path = path.clone();
|
||||
path.push(key);
|
||||
child.do_leaves(path)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn retain<C>(&mut self, callback: C)
|
||||
where
|
||||
C: Fn(&T) -> bool + Copy,
|
||||
{
|
||||
self.children.retain(|_key, child| {
|
||||
child.retain(callback);
|
||||
|
||||
if child.children.is_empty() {
|
||||
(callback)(&child.value)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let result = 2 + 2;
|
||||
assert_eq!(result, 4);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue