pub struct NaryRelation<T: Ord> { /* private fields */ }Expand description
Deterministic exact n-ary relation with a named schema. A deterministic exact n-ary relation with a named schema.
NaryRelation<T> is the first G2 building block for schema-aware
relations. It stores column names explicitly and keeps rows in a BTreeSet
so iteration order is deterministic.
In this initial G2 step, all cells in a row share the same value type T.
§Examples
use relmath::NaryRelation;
let mut passed = NaryRelation::new(["student", "course", "status"])?;
assert_eq!(passed.column_index("course")?, 1);
assert!(passed.insert_row(["Alice", "Math", "passed"])?);
assert!(passed.insert_row(["Alice", "Physics", "passed"])?);
assert!(passed.insert_row(["Bob", "Physics", "in_progress"])?);
let completed = passed.select(|row| row[2] == "passed");
let students = completed.project(["student"])?;
let renamed = students.rename("student", "learner")?;
assert_eq!(passed.arity(), 3);
assert!(completed.contains_row(&["Alice", "Math", "passed"]));
assert_eq!(renamed.schema(), &["learner".to_string()]);Implementations§
Source§impl<T: Ord> NaryRelation<T>
impl<T: Ord> NaryRelation<T>
Sourcepub fn new<I, S>(schema: I) -> Result<Self, NaryRelationError>
pub fn new<I, S>(schema: I) -> Result<Self, NaryRelationError>
Creates an empty n-ary relation with the given schema.
Column names must be unique and non-blank.
Sourcepub fn from_rows<I, S, R, Row>(
schema: I,
rows: R,
) -> Result<Self, NaryRelationError>where
I: IntoIterator<Item = S>,
S: Into<String>,
R: IntoIterator<Item = Row>,
Row: IntoIterator<Item = T>,
pub fn from_rows<I, S, R, Row>(
schema: I,
rows: R,
) -> Result<Self, NaryRelationError>where
I: IntoIterator<Item = S>,
S: Into<String>,
R: IntoIterator<Item = Row>,
Row: IntoIterator<Item = T>,
Creates an n-ary relation from a schema and rows.
Column names must be unique and non-blank, and every row must have the same arity as the schema.
Examples found in repository?
9fn main() -> Result<(), relmath::NaryRelationError> {
10 let people = UnaryRelation::from_values(["Ada", "Bob"]);
11 let parent = BinaryRelation::from_pairs([("Ada", "Bob"), ("Bob", "Cara")]);
12 let enrollments =
13 NaryRelation::from_rows(["student", "course"], [["Ada", "Math"], ["Bob", "Physics"]])?;
14
15 assert_eq!(tuple_count(&people), 2);
16 assert_eq!(tuple_count(&parent), 2);
17 assert_eq!(tuple_count(&enrollments), 2);
18
19 assert_eq!(
20 people.tuples().copied().collect::<Vec<_>>(),
21 vec!["Ada", "Bob"]
22 );
23 assert_eq!(
24 parent.tuples().copied().collect::<Vec<_>>(),
25 vec![("Ada", "Bob"), ("Bob", "Cara")]
26 );
27 assert_eq!(
28 enrollments
29 .tuples()
30 .map(|row| row.to_vec())
31 .collect::<Vec<_>>(),
32 vec![vec!["Ada", "Math"], vec!["Bob", "Physics"]]
33 );
34
35 println!("people: {:?}", people.tuples().copied().collect::<Vec<_>>());
36 println!("parent: {:?}", parent.tuples().copied().collect::<Vec<_>>());
37 println!(
38 "enrollments: {:?}",
39 enrollments
40 .tuples()
41 .map(|row| row.to_vec())
42 .collect::<Vec<_>>()
43 );
44
45 Ok(())
46}Sourcepub fn from_named_rows<I, S, R, K>(
schema: I,
rows: R,
) -> Result<Self, NaryRelationError>where
I: IntoIterator<Item = S>,
S: Into<String>,
R: IntoIterator<Item = BTreeMap<K, T>>,
K: Into<String> + Ord,
pub fn from_named_rows<I, S, R, K>(
schema: I,
rows: R,
) -> Result<Self, NaryRelationError>where
I: IntoIterator<Item = S>,
S: Into<String>,
R: IntoIterator<Item = BTreeMap<K, T>>,
K: Into<String> + Ord,
Creates an n-ary relation from a schema and named rows.
This is the current std-only G2 onboarding boundary. Each input row must provide exactly the schema columns by name. The schema order stays explicit in the relation rather than being inferred from map iteration.
§Examples
use std::collections::BTreeMap;
use relmath::NaryRelation;
let progress = NaryRelation::from_named_rows(
["student", "course", "status"],
[
BTreeMap::from([
("course", "Math"),
("status", "passed"),
("student", "Alice"),
]),
BTreeMap::from([
("course", "Physics"),
("status", "in_progress"),
("student", "Bob"),
]),
],
)?;
assert_eq!(
progress.to_rows(),
vec![
vec!["Alice", "Math", "passed"],
vec!["Bob", "Physics", "in_progress"],
]
);Examples found in repository?
7fn main() -> Result<(), relmath::NaryRelationError> {
8 let progress = NaryRelation::from_named_rows(
9 ["student", "course", "status"],
10 [
11 BTreeMap::from([
12 ("course", "Math"),
13 ("status", "passed"),
14 ("student", "Alice"),
15 ]),
16 BTreeMap::from([
17 ("course", "Physics"),
18 ("status", "passed"),
19 ("student", "Alice"),
20 ]),
21 BTreeMap::from([("course", "Math"), ("status", "passed"), ("student", "Bob")]),
22 BTreeMap::from([
23 ("course", "Physics"),
24 ("status", "in_progress"),
25 ("student", "Bob"),
26 ]),
27 BTreeMap::from([
28 ("course", "Math"),
29 ("status", "passed"),
30 ("student", "Cara"),
31 ]),
32 ],
33 )?;
34 let course_rooms = NaryRelation::from_named_rows(
35 ["course", "room"],
36 [
37 BTreeMap::from([("course", "Math"), ("room", "R101")]),
38 BTreeMap::from([("course", "Physics"), ("room", "R201")]),
39 BTreeMap::from([("course", "History"), ("room", "R301")]),
40 ],
41 )?;
42
43 let completed = progress
44 .select(|row| row[2] == "passed")
45 .project(["student", "course"])?;
46 let scheduled = completed.natural_join(&course_rooms);
47 let by_room = scheduled.group_by(["room"])?;
48 let room_r101 = by_room.group(&["R101"]).expect("expected R101 group");
49 let room_assignments = scheduled.project(["room", "student"])?;
50 let exported_assignments = room_assignments.to_named_rows();
51
52 assert!(completed.contains_row(&["Alice", "Math"]));
53 assert_eq!(
54 scheduled.schema(),
55 &[
56 "student".to_string(),
57 "course".to_string(),
58 "room".to_string(),
59 ]
60 );
61 assert_eq!(
62 scheduled.to_rows(),
63 vec![
64 vec!["Alice", "Math", "R101"],
65 vec!["Alice", "Physics", "R201"],
66 vec!["Bob", "Math", "R101"],
67 vec!["Cara", "Math", "R101"],
68 ]
69 );
70 assert_eq!(by_room.key_schema(), &["room".to_string()]);
71 assert_eq!(by_room.member_schema(), scheduled.schema());
72 assert_eq!(by_room.counts(), vec![(vec!["R101"], 3), (vec!["R201"], 1)]);
73 assert_eq!(
74 room_r101.to_rows(),
75 vec![
76 vec!["Alice", "Math", "R101"],
77 vec!["Bob", "Math", "R101"],
78 vec!["Cara", "Math", "R101"],
79 ]
80 );
81 assert_eq!(
82 room_assignments.to_rows(),
83 vec![
84 vec!["R101", "Alice"],
85 vec!["R101", "Bob"],
86 vec!["R101", "Cara"],
87 vec!["R201", "Alice"],
88 ]
89 );
90 assert_eq!(
91 exported_assignments[0],
92 BTreeMap::from([
93 ("room".to_string(), "R101"),
94 ("student".to_string(), "Alice"),
95 ])
96 );
97
98 println!("scheduled course completions: {:?}", scheduled.to_rows());
99
100 Ok(())
101}Sourcepub fn schema(&self) -> &[String]
pub fn schema(&self) -> &[String]
Returns the schema column names in order.
Examples found in repository?
7fn main() -> Result<(), relmath::NaryRelationError> {
8 let progress = NaryRelation::from_named_rows(
9 ["student", "course", "status"],
10 [
11 BTreeMap::from([
12 ("course", "Math"),
13 ("status", "passed"),
14 ("student", "Alice"),
15 ]),
16 BTreeMap::from([
17 ("course", "Physics"),
18 ("status", "passed"),
19 ("student", "Alice"),
20 ]),
21 BTreeMap::from([("course", "Math"), ("status", "passed"), ("student", "Bob")]),
22 BTreeMap::from([
23 ("course", "Physics"),
24 ("status", "in_progress"),
25 ("student", "Bob"),
26 ]),
27 BTreeMap::from([
28 ("course", "Math"),
29 ("status", "passed"),
30 ("student", "Cara"),
31 ]),
32 ],
33 )?;
34 let course_rooms = NaryRelation::from_named_rows(
35 ["course", "room"],
36 [
37 BTreeMap::from([("course", "Math"), ("room", "R101")]),
38 BTreeMap::from([("course", "Physics"), ("room", "R201")]),
39 BTreeMap::from([("course", "History"), ("room", "R301")]),
40 ],
41 )?;
42
43 let completed = progress
44 .select(|row| row[2] == "passed")
45 .project(["student", "course"])?;
46 let scheduled = completed.natural_join(&course_rooms);
47 let by_room = scheduled.group_by(["room"])?;
48 let room_r101 = by_room.group(&["R101"]).expect("expected R101 group");
49 let room_assignments = scheduled.project(["room", "student"])?;
50 let exported_assignments = room_assignments.to_named_rows();
51
52 assert!(completed.contains_row(&["Alice", "Math"]));
53 assert_eq!(
54 scheduled.schema(),
55 &[
56 "student".to_string(),
57 "course".to_string(),
58 "room".to_string(),
59 ]
60 );
61 assert_eq!(
62 scheduled.to_rows(),
63 vec![
64 vec!["Alice", "Math", "R101"],
65 vec!["Alice", "Physics", "R201"],
66 vec!["Bob", "Math", "R101"],
67 vec!["Cara", "Math", "R101"],
68 ]
69 );
70 assert_eq!(by_room.key_schema(), &["room".to_string()]);
71 assert_eq!(by_room.member_schema(), scheduled.schema());
72 assert_eq!(by_room.counts(), vec![(vec!["R101"], 3), (vec!["R201"], 1)]);
73 assert_eq!(
74 room_r101.to_rows(),
75 vec![
76 vec!["Alice", "Math", "R101"],
77 vec!["Bob", "Math", "R101"],
78 vec!["Cara", "Math", "R101"],
79 ]
80 );
81 assert_eq!(
82 room_assignments.to_rows(),
83 vec![
84 vec!["R101", "Alice"],
85 vec!["R101", "Bob"],
86 vec!["R101", "Cara"],
87 vec!["R201", "Alice"],
88 ]
89 );
90 assert_eq!(
91 exported_assignments[0],
92 BTreeMap::from([
93 ("room".to_string(), "R101"),
94 ("student".to_string(), "Alice"),
95 ])
96 );
97
98 println!("scheduled course completions: {:?}", scheduled.to_rows());
99
100 Ok(())
101}Sourcepub fn column_index(&self, column: &str) -> Result<usize, NaryRelationError>
pub fn column_index(&self, column: &str) -> Result<usize, NaryRelationError>
Returns the zero-based position of a named column.
§Examples
use relmath::NaryRelation;
let students = NaryRelation::<&str>::new(["student", "course"])?;
assert_eq!(students.column_index("student")?, 0);
assert_eq!(students.column_index("course")?, 1);Sourcepub fn insert_row<I>(&mut self, row: I) -> Result<bool, NaryRelationError>where
I: IntoIterator<Item = T>,
pub fn insert_row<I>(&mut self, row: I) -> Result<bool, NaryRelationError>where
I: IntoIterator<Item = T>,
Inserts a row into the relation.
Returns true when the row was not already present.
Sourcepub fn contains_row(&self, row: &[T]) -> bool
pub fn contains_row(&self, row: &[T]) -> bool
Returns true when the relation contains the given row.
Examples found in repository?
7fn main() -> Result<(), relmath::NaryRelationError> {
8 let progress = NaryRelation::from_named_rows(
9 ["student", "course", "status"],
10 [
11 BTreeMap::from([
12 ("course", "Math"),
13 ("status", "passed"),
14 ("student", "Alice"),
15 ]),
16 BTreeMap::from([
17 ("course", "Physics"),
18 ("status", "passed"),
19 ("student", "Alice"),
20 ]),
21 BTreeMap::from([("course", "Math"), ("status", "passed"), ("student", "Bob")]),
22 BTreeMap::from([
23 ("course", "Physics"),
24 ("status", "in_progress"),
25 ("student", "Bob"),
26 ]),
27 BTreeMap::from([
28 ("course", "Math"),
29 ("status", "passed"),
30 ("student", "Cara"),
31 ]),
32 ],
33 )?;
34 let course_rooms = NaryRelation::from_named_rows(
35 ["course", "room"],
36 [
37 BTreeMap::from([("course", "Math"), ("room", "R101")]),
38 BTreeMap::from([("course", "Physics"), ("room", "R201")]),
39 BTreeMap::from([("course", "History"), ("room", "R301")]),
40 ],
41 )?;
42
43 let completed = progress
44 .select(|row| row[2] == "passed")
45 .project(["student", "course"])?;
46 let scheduled = completed.natural_join(&course_rooms);
47 let by_room = scheduled.group_by(["room"])?;
48 let room_r101 = by_room.group(&["R101"]).expect("expected R101 group");
49 let room_assignments = scheduled.project(["room", "student"])?;
50 let exported_assignments = room_assignments.to_named_rows();
51
52 assert!(completed.contains_row(&["Alice", "Math"]));
53 assert_eq!(
54 scheduled.schema(),
55 &[
56 "student".to_string(),
57 "course".to_string(),
58 "room".to_string(),
59 ]
60 );
61 assert_eq!(
62 scheduled.to_rows(),
63 vec![
64 vec!["Alice", "Math", "R101"],
65 vec!["Alice", "Physics", "R201"],
66 vec!["Bob", "Math", "R101"],
67 vec!["Cara", "Math", "R101"],
68 ]
69 );
70 assert_eq!(by_room.key_schema(), &["room".to_string()]);
71 assert_eq!(by_room.member_schema(), scheduled.schema());
72 assert_eq!(by_room.counts(), vec![(vec!["R101"], 3), (vec!["R201"], 1)]);
73 assert_eq!(
74 room_r101.to_rows(),
75 vec![
76 vec!["Alice", "Math", "R101"],
77 vec!["Bob", "Math", "R101"],
78 vec!["Cara", "Math", "R101"],
79 ]
80 );
81 assert_eq!(
82 room_assignments.to_rows(),
83 vec![
84 vec!["R101", "Alice"],
85 vec!["R101", "Bob"],
86 vec!["R101", "Cara"],
87 vec!["R201", "Alice"],
88 ]
89 );
90 assert_eq!(
91 exported_assignments[0],
92 BTreeMap::from([
93 ("room".to_string(), "R101"),
94 ("student".to_string(), "Alice"),
95 ])
96 );
97
98 println!("scheduled course completions: {:?}", scheduled.to_rows());
99
100 Ok(())
101}Sourcepub fn iter(&self) -> impl Iterator<Item = &[T]>
pub fn iter(&self) -> impl Iterator<Item = &[T]>
Returns an iterator over the stored rows in deterministic order.
Sourcepub fn to_rows(&self) -> Vec<Vec<T>>where
T: Clone,
pub fn to_rows(&self) -> Vec<Vec<T>>where
T: Clone,
Returns the rows as a deterministically ordered vector.
Examples found in repository?
7fn main() -> Result<(), relmath::NaryRelationError> {
8 let progress = NaryRelation::from_named_rows(
9 ["student", "course", "status"],
10 [
11 BTreeMap::from([
12 ("course", "Math"),
13 ("status", "passed"),
14 ("student", "Alice"),
15 ]),
16 BTreeMap::from([
17 ("course", "Physics"),
18 ("status", "passed"),
19 ("student", "Alice"),
20 ]),
21 BTreeMap::from([("course", "Math"), ("status", "passed"), ("student", "Bob")]),
22 BTreeMap::from([
23 ("course", "Physics"),
24 ("status", "in_progress"),
25 ("student", "Bob"),
26 ]),
27 BTreeMap::from([
28 ("course", "Math"),
29 ("status", "passed"),
30 ("student", "Cara"),
31 ]),
32 ],
33 )?;
34 let course_rooms = NaryRelation::from_named_rows(
35 ["course", "room"],
36 [
37 BTreeMap::from([("course", "Math"), ("room", "R101")]),
38 BTreeMap::from([("course", "Physics"), ("room", "R201")]),
39 BTreeMap::from([("course", "History"), ("room", "R301")]),
40 ],
41 )?;
42
43 let completed = progress
44 .select(|row| row[2] == "passed")
45 .project(["student", "course"])?;
46 let scheduled = completed.natural_join(&course_rooms);
47 let by_room = scheduled.group_by(["room"])?;
48 let room_r101 = by_room.group(&["R101"]).expect("expected R101 group");
49 let room_assignments = scheduled.project(["room", "student"])?;
50 let exported_assignments = room_assignments.to_named_rows();
51
52 assert!(completed.contains_row(&["Alice", "Math"]));
53 assert_eq!(
54 scheduled.schema(),
55 &[
56 "student".to_string(),
57 "course".to_string(),
58 "room".to_string(),
59 ]
60 );
61 assert_eq!(
62 scheduled.to_rows(),
63 vec![
64 vec!["Alice", "Math", "R101"],
65 vec!["Alice", "Physics", "R201"],
66 vec!["Bob", "Math", "R101"],
67 vec!["Cara", "Math", "R101"],
68 ]
69 );
70 assert_eq!(by_room.key_schema(), &["room".to_string()]);
71 assert_eq!(by_room.member_schema(), scheduled.schema());
72 assert_eq!(by_room.counts(), vec![(vec!["R101"], 3), (vec!["R201"], 1)]);
73 assert_eq!(
74 room_r101.to_rows(),
75 vec![
76 vec!["Alice", "Math", "R101"],
77 vec!["Bob", "Math", "R101"],
78 vec!["Cara", "Math", "R101"],
79 ]
80 );
81 assert_eq!(
82 room_assignments.to_rows(),
83 vec![
84 vec!["R101", "Alice"],
85 vec!["R101", "Bob"],
86 vec!["R101", "Cara"],
87 vec!["R201", "Alice"],
88 ]
89 );
90 assert_eq!(
91 exported_assignments[0],
92 BTreeMap::from([
93 ("room".to_string(), "R101"),
94 ("student".to_string(), "Alice"),
95 ])
96 );
97
98 println!("scheduled course completions: {:?}", scheduled.to_rows());
99
100 Ok(())
101}Sourcepub fn to_named_rows(&self) -> Vec<BTreeMap<String, T>>where
T: Clone,
pub fn to_named_rows(&self) -> Vec<BTreeMap<String, T>>where
T: Clone,
Exports the relation as named rows.
The returned vector follows the relation’s deterministic row order.
Each row is materialized as a BTreeMap, so key lookup is by column
name rather than schema position. Preserve Self::schema separately
when schema order matters to a downstream consumer.
§Examples
use std::collections::BTreeMap;
use relmath::NaryRelation;
let progress = NaryRelation::from_rows(
["student", "course"],
[["Alice", "Math"], ["Bob", "Physics"]],
)?;
assert_eq!(
progress.to_named_rows(),
vec![
BTreeMap::from([
("course".to_string(), "Math"),
("student".to_string(), "Alice"),
]),
BTreeMap::from([
("course".to_string(), "Physics"),
("student".to_string(), "Bob"),
]),
]
);Examples found in repository?
7fn main() -> Result<(), relmath::NaryRelationError> {
8 let progress = NaryRelation::from_named_rows(
9 ["student", "course", "status"],
10 [
11 BTreeMap::from([
12 ("course", "Math"),
13 ("status", "passed"),
14 ("student", "Alice"),
15 ]),
16 BTreeMap::from([
17 ("course", "Physics"),
18 ("status", "passed"),
19 ("student", "Alice"),
20 ]),
21 BTreeMap::from([("course", "Math"), ("status", "passed"), ("student", "Bob")]),
22 BTreeMap::from([
23 ("course", "Physics"),
24 ("status", "in_progress"),
25 ("student", "Bob"),
26 ]),
27 BTreeMap::from([
28 ("course", "Math"),
29 ("status", "passed"),
30 ("student", "Cara"),
31 ]),
32 ],
33 )?;
34 let course_rooms = NaryRelation::from_named_rows(
35 ["course", "room"],
36 [
37 BTreeMap::from([("course", "Math"), ("room", "R101")]),
38 BTreeMap::from([("course", "Physics"), ("room", "R201")]),
39 BTreeMap::from([("course", "History"), ("room", "R301")]),
40 ],
41 )?;
42
43 let completed = progress
44 .select(|row| row[2] == "passed")
45 .project(["student", "course"])?;
46 let scheduled = completed.natural_join(&course_rooms);
47 let by_room = scheduled.group_by(["room"])?;
48 let room_r101 = by_room.group(&["R101"]).expect("expected R101 group");
49 let room_assignments = scheduled.project(["room", "student"])?;
50 let exported_assignments = room_assignments.to_named_rows();
51
52 assert!(completed.contains_row(&["Alice", "Math"]));
53 assert_eq!(
54 scheduled.schema(),
55 &[
56 "student".to_string(),
57 "course".to_string(),
58 "room".to_string(),
59 ]
60 );
61 assert_eq!(
62 scheduled.to_rows(),
63 vec![
64 vec!["Alice", "Math", "R101"],
65 vec!["Alice", "Physics", "R201"],
66 vec!["Bob", "Math", "R101"],
67 vec!["Cara", "Math", "R101"],
68 ]
69 );
70 assert_eq!(by_room.key_schema(), &["room".to_string()]);
71 assert_eq!(by_room.member_schema(), scheduled.schema());
72 assert_eq!(by_room.counts(), vec![(vec!["R101"], 3), (vec!["R201"], 1)]);
73 assert_eq!(
74 room_r101.to_rows(),
75 vec![
76 vec!["Alice", "Math", "R101"],
77 vec!["Bob", "Math", "R101"],
78 vec!["Cara", "Math", "R101"],
79 ]
80 );
81 assert_eq!(
82 room_assignments.to_rows(),
83 vec![
84 vec!["R101", "Alice"],
85 vec!["R101", "Bob"],
86 vec!["R101", "Cara"],
87 vec!["R201", "Alice"],
88 ]
89 );
90 assert_eq!(
91 exported_assignments[0],
92 BTreeMap::from([
93 ("room".to_string(), "R101"),
94 ("student".to_string(), "Alice"),
95 ])
96 );
97
98 println!("scheduled course completions: {:?}", scheduled.to_rows());
99
100 Ok(())
101}Sourcepub fn group_by<I, S>(
&self,
columns: I,
) -> Result<GroupedRelation<T>, NaryRelationError>
pub fn group_by<I, S>( &self, columns: I, ) -> Result<GroupedRelation<T>, NaryRelationError>
Groups the relation by the named key columns.
Group keys follow the exact order of columns. Empty key selections,
duplicate key columns, and unknown columns are rejected by the current
exact core.
Each member relation keeps the original relation schema and contains the
subset of rows whose projected key matches the group key. Groups are
stored in a BTreeMap, so group iteration order is deterministic.
The first exact aggregate over the grouped output is
GroupedRelation::counts, which reports the number of stored rows in
each group.
§Examples
use relmath::NaryRelation;
let completed = NaryRelation::from_rows(
["student", "course", "term"],
[
["Alice", "Math", "Fall"],
["Alice", "Physics", "Fall"],
["Bob", "Math", "Spring"],
],
)?;
let grouped = completed.group_by(["term", "student"])?;
assert_eq!(
grouped.key_schema(),
&["term".to_string(), "student".to_string()]
);
assert_eq!(
grouped.counts(),
vec![(vec!["Fall", "Alice"], 2), (vec!["Spring", "Bob"], 1)]
);Examples found in repository?
7fn main() -> Result<(), relmath::NaryRelationError> {
8 let progress = NaryRelation::from_named_rows(
9 ["student", "course", "status"],
10 [
11 BTreeMap::from([
12 ("course", "Math"),
13 ("status", "passed"),
14 ("student", "Alice"),
15 ]),
16 BTreeMap::from([
17 ("course", "Physics"),
18 ("status", "passed"),
19 ("student", "Alice"),
20 ]),
21 BTreeMap::from([("course", "Math"), ("status", "passed"), ("student", "Bob")]),
22 BTreeMap::from([
23 ("course", "Physics"),
24 ("status", "in_progress"),
25 ("student", "Bob"),
26 ]),
27 BTreeMap::from([
28 ("course", "Math"),
29 ("status", "passed"),
30 ("student", "Cara"),
31 ]),
32 ],
33 )?;
34 let course_rooms = NaryRelation::from_named_rows(
35 ["course", "room"],
36 [
37 BTreeMap::from([("course", "Math"), ("room", "R101")]),
38 BTreeMap::from([("course", "Physics"), ("room", "R201")]),
39 BTreeMap::from([("course", "History"), ("room", "R301")]),
40 ],
41 )?;
42
43 let completed = progress
44 .select(|row| row[2] == "passed")
45 .project(["student", "course"])?;
46 let scheduled = completed.natural_join(&course_rooms);
47 let by_room = scheduled.group_by(["room"])?;
48 let room_r101 = by_room.group(&["R101"]).expect("expected R101 group");
49 let room_assignments = scheduled.project(["room", "student"])?;
50 let exported_assignments = room_assignments.to_named_rows();
51
52 assert!(completed.contains_row(&["Alice", "Math"]));
53 assert_eq!(
54 scheduled.schema(),
55 &[
56 "student".to_string(),
57 "course".to_string(),
58 "room".to_string(),
59 ]
60 );
61 assert_eq!(
62 scheduled.to_rows(),
63 vec![
64 vec!["Alice", "Math", "R101"],
65 vec!["Alice", "Physics", "R201"],
66 vec!["Bob", "Math", "R101"],
67 vec!["Cara", "Math", "R101"],
68 ]
69 );
70 assert_eq!(by_room.key_schema(), &["room".to_string()]);
71 assert_eq!(by_room.member_schema(), scheduled.schema());
72 assert_eq!(by_room.counts(), vec![(vec!["R101"], 3), (vec!["R201"], 1)]);
73 assert_eq!(
74 room_r101.to_rows(),
75 vec![
76 vec!["Alice", "Math", "R101"],
77 vec!["Bob", "Math", "R101"],
78 vec!["Cara", "Math", "R101"],
79 ]
80 );
81 assert_eq!(
82 room_assignments.to_rows(),
83 vec![
84 vec!["R101", "Alice"],
85 vec!["R101", "Bob"],
86 vec!["R101", "Cara"],
87 vec!["R201", "Alice"],
88 ]
89 );
90 assert_eq!(
91 exported_assignments[0],
92 BTreeMap::from([
93 ("room".to_string(), "R101"),
94 ("student".to_string(), "Alice"),
95 ])
96 );
97
98 println!("scheduled course completions: {:?}", scheduled.to_rows());
99
100 Ok(())
101}Sourcepub fn select<F>(&self, predicate: F) -> Self
pub fn select<F>(&self, predicate: F) -> Self
Returns the subset of rows that satisfy predicate.
The output keeps the same schema as self. Surviving rows remain in the
deterministic order induced by the underlying BTreeSet.
§Examples
use relmath::NaryRelation;
let progress = NaryRelation::from_rows(
["student", "course", "status"],
[
["Alice", "Math", "passed"],
["Alice", "Physics", "passed"],
["Bob", "Physics", "in_progress"],
],
)?;
let completed = progress.select(|row| row[2] == "passed");
assert_eq!(
completed.to_rows(),
vec![
vec!["Alice", "Math", "passed"],
vec!["Alice", "Physics", "passed"],
]
);Examples found in repository?
7fn main() -> Result<(), relmath::NaryRelationError> {
8 let progress = NaryRelation::from_named_rows(
9 ["student", "course", "status"],
10 [
11 BTreeMap::from([
12 ("course", "Math"),
13 ("status", "passed"),
14 ("student", "Alice"),
15 ]),
16 BTreeMap::from([
17 ("course", "Physics"),
18 ("status", "passed"),
19 ("student", "Alice"),
20 ]),
21 BTreeMap::from([("course", "Math"), ("status", "passed"), ("student", "Bob")]),
22 BTreeMap::from([
23 ("course", "Physics"),
24 ("status", "in_progress"),
25 ("student", "Bob"),
26 ]),
27 BTreeMap::from([
28 ("course", "Math"),
29 ("status", "passed"),
30 ("student", "Cara"),
31 ]),
32 ],
33 )?;
34 let course_rooms = NaryRelation::from_named_rows(
35 ["course", "room"],
36 [
37 BTreeMap::from([("course", "Math"), ("room", "R101")]),
38 BTreeMap::from([("course", "Physics"), ("room", "R201")]),
39 BTreeMap::from([("course", "History"), ("room", "R301")]),
40 ],
41 )?;
42
43 let completed = progress
44 .select(|row| row[2] == "passed")
45 .project(["student", "course"])?;
46 let scheduled = completed.natural_join(&course_rooms);
47 let by_room = scheduled.group_by(["room"])?;
48 let room_r101 = by_room.group(&["R101"]).expect("expected R101 group");
49 let room_assignments = scheduled.project(["room", "student"])?;
50 let exported_assignments = room_assignments.to_named_rows();
51
52 assert!(completed.contains_row(&["Alice", "Math"]));
53 assert_eq!(
54 scheduled.schema(),
55 &[
56 "student".to_string(),
57 "course".to_string(),
58 "room".to_string(),
59 ]
60 );
61 assert_eq!(
62 scheduled.to_rows(),
63 vec![
64 vec!["Alice", "Math", "R101"],
65 vec!["Alice", "Physics", "R201"],
66 vec!["Bob", "Math", "R101"],
67 vec!["Cara", "Math", "R101"],
68 ]
69 );
70 assert_eq!(by_room.key_schema(), &["room".to_string()]);
71 assert_eq!(by_room.member_schema(), scheduled.schema());
72 assert_eq!(by_room.counts(), vec![(vec!["R101"], 3), (vec!["R201"], 1)]);
73 assert_eq!(
74 room_r101.to_rows(),
75 vec![
76 vec!["Alice", "Math", "R101"],
77 vec!["Bob", "Math", "R101"],
78 vec!["Cara", "Math", "R101"],
79 ]
80 );
81 assert_eq!(
82 room_assignments.to_rows(),
83 vec![
84 vec!["R101", "Alice"],
85 vec!["R101", "Bob"],
86 vec!["R101", "Cara"],
87 vec!["R201", "Alice"],
88 ]
89 );
90 assert_eq!(
91 exported_assignments[0],
92 BTreeMap::from([
93 ("room".to_string(), "R101"),
94 ("student".to_string(), "Alice"),
95 ])
96 );
97
98 println!("scheduled course completions: {:?}", scheduled.to_rows());
99
100 Ok(())
101}Sourcepub fn project<I, S>(&self, columns: I) -> Result<Self, NaryRelationError>
pub fn project<I, S>(&self, columns: I) -> Result<Self, NaryRelationError>
Projects the relation onto the named columns in the requested order.
The output schema follows the exact order of columns. Duplicate
column names, unknown columns, and empty projections are rejected by the
current exact core.
§Examples
use relmath::NaryRelation;
let passed = NaryRelation::from_rows(
["student", "course", "status"],
[
["Alice", "Math", "passed"],
["Cara", "Math", "passed"],
["Alice", "Physics", "passed"],
],
)?;
let projected = passed.project(["course", "student"])?;
assert_eq!(
projected.schema(),
&["course".to_string(), "student".to_string()]
);
assert_eq!(
projected.to_rows(),
vec![
vec!["Math", "Alice"],
vec!["Math", "Cara"],
vec!["Physics", "Alice"],
]
);Examples found in repository?
7fn main() -> Result<(), relmath::NaryRelationError> {
8 let progress = NaryRelation::from_named_rows(
9 ["student", "course", "status"],
10 [
11 BTreeMap::from([
12 ("course", "Math"),
13 ("status", "passed"),
14 ("student", "Alice"),
15 ]),
16 BTreeMap::from([
17 ("course", "Physics"),
18 ("status", "passed"),
19 ("student", "Alice"),
20 ]),
21 BTreeMap::from([("course", "Math"), ("status", "passed"), ("student", "Bob")]),
22 BTreeMap::from([
23 ("course", "Physics"),
24 ("status", "in_progress"),
25 ("student", "Bob"),
26 ]),
27 BTreeMap::from([
28 ("course", "Math"),
29 ("status", "passed"),
30 ("student", "Cara"),
31 ]),
32 ],
33 )?;
34 let course_rooms = NaryRelation::from_named_rows(
35 ["course", "room"],
36 [
37 BTreeMap::from([("course", "Math"), ("room", "R101")]),
38 BTreeMap::from([("course", "Physics"), ("room", "R201")]),
39 BTreeMap::from([("course", "History"), ("room", "R301")]),
40 ],
41 )?;
42
43 let completed = progress
44 .select(|row| row[2] == "passed")
45 .project(["student", "course"])?;
46 let scheduled = completed.natural_join(&course_rooms);
47 let by_room = scheduled.group_by(["room"])?;
48 let room_r101 = by_room.group(&["R101"]).expect("expected R101 group");
49 let room_assignments = scheduled.project(["room", "student"])?;
50 let exported_assignments = room_assignments.to_named_rows();
51
52 assert!(completed.contains_row(&["Alice", "Math"]));
53 assert_eq!(
54 scheduled.schema(),
55 &[
56 "student".to_string(),
57 "course".to_string(),
58 "room".to_string(),
59 ]
60 );
61 assert_eq!(
62 scheduled.to_rows(),
63 vec![
64 vec!["Alice", "Math", "R101"],
65 vec!["Alice", "Physics", "R201"],
66 vec!["Bob", "Math", "R101"],
67 vec!["Cara", "Math", "R101"],
68 ]
69 );
70 assert_eq!(by_room.key_schema(), &["room".to_string()]);
71 assert_eq!(by_room.member_schema(), scheduled.schema());
72 assert_eq!(by_room.counts(), vec![(vec!["R101"], 3), (vec!["R201"], 1)]);
73 assert_eq!(
74 room_r101.to_rows(),
75 vec![
76 vec!["Alice", "Math", "R101"],
77 vec!["Bob", "Math", "R101"],
78 vec!["Cara", "Math", "R101"],
79 ]
80 );
81 assert_eq!(
82 room_assignments.to_rows(),
83 vec![
84 vec!["R101", "Alice"],
85 vec!["R101", "Bob"],
86 vec!["R101", "Cara"],
87 vec!["R201", "Alice"],
88 ]
89 );
90 assert_eq!(
91 exported_assignments[0],
92 BTreeMap::from([
93 ("room".to_string(), "R101"),
94 ("student".to_string(), "Alice"),
95 ])
96 );
97
98 println!("scheduled course completions: {:?}", scheduled.to_rows());
99
100 Ok(())
101}Sourcepub fn rename<S>(&self, from: &str, to: S) -> Result<Self, NaryRelationError>
pub fn rename<S>(&self, from: &str, to: S) -> Result<Self, NaryRelationError>
Returns a relation with one column renamed.
Renaming a column to its current name is a no-op. The new column name must be non-blank and must not duplicate another column in the schema.
§Examples
use relmath::NaryRelation;
let completed = NaryRelation::from_rows(
["student", "course"],
[["Alice", "Math"], ["Bob", "Physics"]],
)?;
let renamed = completed.rename("student", "learner")?;
assert_eq!(
renamed.schema(),
&["learner".to_string(), "course".to_string()]
);
assert_eq!(
renamed.to_rows(),
vec![vec!["Alice", "Math"], vec!["Bob", "Physics"]]
);Sourcepub fn union(&self, other: &Self) -> Result<Self, NaryRelationError>where
T: Clone,
pub fn union(&self, other: &Self) -> Result<Self, NaryRelationError>where
T: Clone,
Returns the union of self and other when schemas match exactly.
Schema compatibility for the current exact core means exact schema equality, including column order.
§Examples
use relmath::NaryRelation;
let left = NaryRelation::from_rows(["student"], [["Alice"], ["Bob"]])?;
let right = NaryRelation::from_rows(["student"], [["Bob"], ["Cara"]])?;
let union = left.union(&right)?;
assert_eq!(
union.to_rows(),
vec![vec!["Alice"], vec!["Bob"], vec!["Cara"]]
);Sourcepub fn intersection(&self, other: &Self) -> Result<Self, NaryRelationError>where
T: Clone,
pub fn intersection(&self, other: &Self) -> Result<Self, NaryRelationError>where
T: Clone,
Returns the intersection of self and other when schemas match
exactly.
Schema compatibility for the current exact core means exact schema equality, including column order.
§Examples
use relmath::NaryRelation;
let left = NaryRelation::from_rows(["student"], [["Alice"], ["Bob"]])?;
let right = NaryRelation::from_rows(["student"], [["Bob"], ["Cara"]])?;
let intersection = left.intersection(&right)?;
assert_eq!(intersection.to_rows(), vec![vec!["Bob"]]);Sourcepub fn difference(&self, other: &Self) -> Result<Self, NaryRelationError>where
T: Clone,
pub fn difference(&self, other: &Self) -> Result<Self, NaryRelationError>where
T: Clone,
Returns the set difference self \ other when schemas match exactly.
Schema compatibility for the current exact core means exact schema equality, including column order.
§Examples
use relmath::NaryRelation;
let left = NaryRelation::from_rows(["student"], [["Alice"], ["Bob"]])?;
let right = NaryRelation::from_rows(["student"], [["Bob"], ["Cara"]])?;
let only_left = left.difference(&right)?;
assert_eq!(only_left.to_rows(), vec![vec!["Alice"]]);Sourcepub fn natural_join(&self, other: &Self) -> Selfwhere
T: Clone,
pub fn natural_join(&self, other: &Self) -> Selfwhere
T: Clone,
Returns the natural join of self and other.
Shared column names constrain row matching: a pair of rows joins only when every shared column has equal values on both sides. When the schemas are disjoint, natural join behaves as a cartesian product.
The output schema keeps the entire left-hand schema in order, followed
by the right-hand columns that are not shared, in their original order.
Output rows are stored in a BTreeSet, so iteration remains
deterministic. When no rows match, the result is empty but still keeps
the joined schema.
§Examples
use relmath::NaryRelation;
let completed = NaryRelation::from_rows(
["student", "course"],
[
["Alice", "Math"],
["Alice", "Physics"],
["Bob", "Math"],
],
)?;
let rooms = NaryRelation::from_rows(
["course", "room"],
[["Math", "R101"], ["Physics", "R201"]],
)?;
let scheduled = completed.natural_join(&rooms);
assert_eq!(
scheduled.schema(),
&["student".to_string(), "course".to_string(), "room".to_string()]
);
assert_eq!(
scheduled.to_rows(),
vec![
vec!["Alice", "Math", "R101"],
vec!["Alice", "Physics", "R201"],
vec!["Bob", "Math", "R101"],
]
);Examples found in repository?
7fn main() -> Result<(), relmath::NaryRelationError> {
8 let progress = NaryRelation::from_named_rows(
9 ["student", "course", "status"],
10 [
11 BTreeMap::from([
12 ("course", "Math"),
13 ("status", "passed"),
14 ("student", "Alice"),
15 ]),
16 BTreeMap::from([
17 ("course", "Physics"),
18 ("status", "passed"),
19 ("student", "Alice"),
20 ]),
21 BTreeMap::from([("course", "Math"), ("status", "passed"), ("student", "Bob")]),
22 BTreeMap::from([
23 ("course", "Physics"),
24 ("status", "in_progress"),
25 ("student", "Bob"),
26 ]),
27 BTreeMap::from([
28 ("course", "Math"),
29 ("status", "passed"),
30 ("student", "Cara"),
31 ]),
32 ],
33 )?;
34 let course_rooms = NaryRelation::from_named_rows(
35 ["course", "room"],
36 [
37 BTreeMap::from([("course", "Math"), ("room", "R101")]),
38 BTreeMap::from([("course", "Physics"), ("room", "R201")]),
39 BTreeMap::from([("course", "History"), ("room", "R301")]),
40 ],
41 )?;
42
43 let completed = progress
44 .select(|row| row[2] == "passed")
45 .project(["student", "course"])?;
46 let scheduled = completed.natural_join(&course_rooms);
47 let by_room = scheduled.group_by(["room"])?;
48 let room_r101 = by_room.group(&["R101"]).expect("expected R101 group");
49 let room_assignments = scheduled.project(["room", "student"])?;
50 let exported_assignments = room_assignments.to_named_rows();
51
52 assert!(completed.contains_row(&["Alice", "Math"]));
53 assert_eq!(
54 scheduled.schema(),
55 &[
56 "student".to_string(),
57 "course".to_string(),
58 "room".to_string(),
59 ]
60 );
61 assert_eq!(
62 scheduled.to_rows(),
63 vec![
64 vec!["Alice", "Math", "R101"],
65 vec!["Alice", "Physics", "R201"],
66 vec!["Bob", "Math", "R101"],
67 vec!["Cara", "Math", "R101"],
68 ]
69 );
70 assert_eq!(by_room.key_schema(), &["room".to_string()]);
71 assert_eq!(by_room.member_schema(), scheduled.schema());
72 assert_eq!(by_room.counts(), vec![(vec!["R101"], 3), (vec!["R201"], 1)]);
73 assert_eq!(
74 room_r101.to_rows(),
75 vec![
76 vec!["Alice", "Math", "R101"],
77 vec!["Bob", "Math", "R101"],
78 vec!["Cara", "Math", "R101"],
79 ]
80 );
81 assert_eq!(
82 room_assignments.to_rows(),
83 vec![
84 vec!["R101", "Alice"],
85 vec!["R101", "Bob"],
86 vec!["R101", "Cara"],
87 vec!["R201", "Alice"],
88 ]
89 );
90 assert_eq!(
91 exported_assignments[0],
92 BTreeMap::from([
93 ("room".to_string(), "R101"),
94 ("student".to_string(), "Alice"),
95 ])
96 );
97
98 println!("scheduled course completions: {:?}", scheduled.to_rows());
99
100 Ok(())
101}Trait Implementations§
Source§impl<T: Clone + Ord> Clone for NaryRelation<T>
impl<T: Clone + Ord> Clone for NaryRelation<T>
Source§fn clone(&self) -> NaryRelation<T>
fn clone(&self) -> NaryRelation<T>
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more