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