#python #comprehension #hash-map #list #set #macro #collection

comprehend

Python like list, set and hashmap comprehensions via macros

2 releases

0.1.1 Mar 11, 2024
0.1.0 Mar 11, 2024

#2442 in Data structures

MIT/Apache

20KB
313 lines

Comprehend

Python like list, set and hashmap comprehensions in Rust via macros.


lib.rs:

Comprehension

Python like list, set and hashmap comprehensions for Rust as efficiently as possible.

Due to how Python handles comprehensions, a one to one translation is not possible, atleast not without resorting to cloning everything. When using this library, its up to the user to clone if necessary.

Upholds Rust ownerships and borrow rules, passing by value WILL consume the collection.

comp! returns a iterator over the elements. compco! includes a .collect() call.

Examples

Basic array comprehension

let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let y: Vec<_> = comp![2*x, for x in v].collect();
assert_eq!(y, vec![2, 4,6, 8, 10, 12, 14, 16, 18, 20]);

Nested array comprehension

let v = vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]];
let y: Vec<_> = comp![2*p, for x in v, for p in x].collect();
assert_eq!(y, vec![2, 4, 6, 8, 10, 12, 14, 16, 18]);

Creating combinations of two arrays, must use clone!

let v = vec![1, 2];
let z = vec![3,4];
let y: Vec<_> = comp![(x,y), for x in v, for y in z.clone()].collect();
assert_eq!(y,vec![(1,3),(1,4),(2,3),(2,4)]);

Use with filters Create a vector of vectors of 3 indices which are all less than 3, and add up to 4.

let y: Vec<_> = comp![vec![i, j, k], for i in 0..3, for j in 0..3, for k in 0..3, if i+j+k == 4].collect();
assert_eq!(y,vec![[0,2,2],[1,1,2],[1,2,1],[2,0,2],[2,1,1],[2,2,0]]);

Basic hashmap comprehension

let v = vec![1, 2, 3, 4];
let y: HashMap<_,_> = comp!{x=>2*x, for x in v}.collect();
assert_eq!(y, HashMap::from([(1, 2), (2, 4), (3, 6), (4, 8)]));

Hashmap comprehension can be also nested used with filters or the special => syntax.

Special '=>' syntax when using nested comprehensions, to do an operation on an inner loop. For example assign the first variable as value to the other numbers as keys in the array.

 # use std::collections::HashMap;
 # use comprehend::comp;
 let v: Vec<Vec<_>> = vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]];
 #[allow(redundant_semicolons)]
 let y: HashMap<i32,i32> =
 comp![p=>z.unwrap(), for x in v => {let mut y = x.into_iter(); let z = y.next();}, for p in y].collect();
 assert_eq!(y, HashMap::from([(2, 1), (3, 1), (5, 4), (6, 4), (8, 7), (9, 7)]));

Would be equivalent to this:

let v: Vec<Vec<_>> = vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]];
#[allow(redundant_semicolons)]
let y: HashMap<i32,i32> =
comp![{let mut y = x.into_iter(); let z = y.next(); comp![p=>z.unwrap(),for p in y]}, for x in v].flatten().collect();
assert_eq!(y, HashMap::from([(2, 1), (3, 1), (5, 4), (6, 4), (8, 7), (9, 7)]));

No runtime deps