Generate vectors (+other structures) with a macro of similar syntax to list comprehensions in Python! + with localized declarations from Haskell
- Macros
- Vector (list) Comprehensions
- HashMap (dictionary) Comprehensions
- HashMap (dictionary) Literal
- Preallocating Vector (list) Comprehensions
- Preallocating HashMap (dictionary) Comprehensions
- Preallocating HashMap (dictionary) Literal
- A set of macros to emulate list/array and dictionary/hashtable comprehensions with syntax inspired primarily by Python
- Variants for preallocation of memory. Remove reallocation initiated by many
push
es orinsert
s - Use custom datastructures
- Includes some additional macros for HashMap literals
- Inline localized
let
s andif
s at any level for complete flexibility - The only limit is (probably) your imagination and the user-manageable max macro recursion depth that can be controlled with
#[recursion_limit = "some depth"]
- you are almost certain to not hit the default recursion depth under typical use of these macros
- vec (list) comprehension
comp![x; for x in 1..4] -> vec![1, 2, 3]
- preallocated vec (list) comprehension
comp_pre![x; for x in 1..4] -> vec![1, 2, 3]
- hashmap (dict) comprehension
dcomp!{x => y+z; for x in 1..4, let y=x*x+4, let z = 3*y+x, if z>20} -> dict!{2 => 34, 3 => 55}
- preallocated hashmap (dict) comprehension
dcomp_pre!{x => y+zz*z; for x in 1..4, let y=x*x+4, let z = 3*y+x, if x>1; for yy in 1..10, let zz= yy+1, if yy<3} -> dict! {3=> 139, 2=> 86}
- hashmap (dict) literal
dict!{3 => (3, 3), 1 => (1, 1), 2 => (2, 2)} -> HashMap {3 : (3, 3), 1 : (1, 1), 2 : (2, 2)}
- preallocated hashmap (dict) literal
dict_pre!{2=> dict_pre!{2 => 34}, 3 => dict_pre!{3 => 55}} -> HashMap {2 : {2 : 34}, 3: {3 : 55}}
- Any
Iterator
or implementor ofIntoIterator
- Inline localized declarations
let
s and conditionalsif
s at any level for total flexibility
//basic
comp![x; for x in 1..4] //vec![1, 2, 3]
//use anything implementing Iterator or IntoIterator (i.e. anything accepted by traditional `for` loops)
comp![x; for x in vec![8, 6, 7, 5, 3, 0, 9]] -> vec![8, 6, 7, 5, 3, 0, 9]
//tuples (of any length - length 2 shown)
comp![(x, y); for (x,y) in (1..4).zip(1..4)] -> vec![(1, 1), (2, 2), (3, 3)]
//conditioning (filtering)
comp![x; for x in 1..4, if x>1] -> vec![2, 3]
//localized declarations (like haskell)
comp![y; for x in 1..4, let y=x*x+4] -> vec![5, 8, 13]
//nesting
comp![comp![y2+z2; for x2 in 1..x, let y2=x*x+4, let z2 = 3*y+x, if z2>20]; for x in 1..4; let y=x*x+4; if x>1] -> vec![vec![34], vec![55, 55]]
//localized declarations w/ conditioning
comp![y; for x in 1..4, let y=x*x+4, if x>1] -> vec![8, 13]
//multiple localized declarations w/ conditioning
comp![y+z; for x in 1..4, let y=x*x+4, let z = 3*y+x, if z>20] -> vec![34, 55]
//multiple iterators and multiple localized declarations w/ conditioning
comp![y+zz*z; for x in 1..4, let y=x*x+4, let z = 3*y+x; for yy in 1..10, let zz= yy+1, if yy<3 && x>1] -> vec![60, 86, 97, 139]
//the same thing can be written using a split conditional to reduce the number of outer loops
comp![y+zz*z; for x in 1..4, let y=x*x+4, let z = 3*y+x, if x>1; for yy in 1..10, let zz= yy+1, if yy<3] -> vec![60, 86, 97, 139]
//use existing vector (e.g. can preallocate and touch memory to prevent any reallocation if you know the size of the final vector beforehand)
let myvec = vec![8, 6, 7, 5, 3, 0, 9];
comp![y+zz*z; for x in 1..4; let y=x*x+4; let z = 3*y+x; for yy in 1..10; let zz= yy+1; if yy<3 && x>1; using myvec] -> vec![8, 6, 7, 5, 3, 0, 9, 60, 86, 97, 139]
//use custom data structures with .push method
let linked_list = LinkedList::new();
comp![using linked_list, x; for x in 1..4] -> Node(1) -> Node(2) -> Node(3)
//unlimited complexity (up to user manageable) macro recursion limit
comp![y+zz*z; for x in 1..4, let y=x*x+4, let z = 3*y+x, if z>20; for yy in 1..10, let zz= yy+1; for _yyy in 1..10, if yy>7; for _i in 1..3] ->
vec![
242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242,
242, 242, 268, 268, 268, 268, 268, 268, 268, 268, 268, 268, 268, 268, 268, 268,
268, 268, 268, 268, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391,
391, 391, 391, 391, 391, 391, 433, 433, 433, 433, 433, 433, 433, 433, 433, 433,
433, 433, 433, 433, 433, 433, 433, 433
]
- Similar to
comp!
except fordcomp!
the expression inserted is of the formkey => value
//basic
dcomp![x*x => x; for x in 1..4] -> dict! {9=> 3, 1=> 1, 4=> 2}
//use anything implementing Iterator or IntoIterator (i.e. anything accepted by traditional `for` loops)
dcomp!{format!("Hello {:?}", x) => x; for x in vec![8, 6, 7, 5, 3, 0, 9]} -> {"Hello 9": 9, "Hello 7": 7, "Hello 6": 6, "Hello 5": 5, "Hello 3": 3, "Hello 0": 0, "Hello 8": 8}
//any pattern
dcomp!{x=>(x, y); for (x,y) in (1..4).zip(1..4)} -> dict! {3=> (3, 3), 1=> (1, 1), 2=> (2, 2)}
//any complexity
dcomp![x=>y+zz*z; for x in 1..4, let y=x*x+4, let z = 3*y+x, if z>20; for yy in 1..10, let zz= yy+1; for _yyy in 1..10, if yy>7; for _i in 1..3] -> dict! {3=> 433, 2=> 268}
- Write
HashMap
s in literal form
dict!{"hello" => 5, "world" => 13, "!" => 8}
- These macros infer the size of the final data structure by accounting for the lower bounds of each
Iterator
as given by.size_hint()
and attempts toreserve
this memory - There are potential performance improvements from this strategy
- The difference between the
capacity
andlen
of the created data structure can be greater than if using the non-preallocated variants - Best used for large comprehensions (or literals) with iterators whose
.size_hint()
is of good accuracy - The user can always call
shrink_to_fit
on the final value to free memory
- see Vector (list) Comprehension for examples
- this differs from
comp!
in that before inserting into aVec
, this macro infers the size of the finalVec
by accounting for the lower bounds of eachIterator
as given by.size_hint()
and attempts toreserve
this memory
- see HashMap (dictionary) Comprehension for examples
- this differs from
dcomp!
in that before inserting into aHashMap
, this macro infers the size of the finalVec
by accounting for the lower bounds of eachIterator
as given by.size_hint()
and attempts toreserve
this memory
- see HashMap (dictionary) Literal for examples
- this differs from
dict!
in that before inserting into aHashMap
, this macro infers the size of the finalHashMap
by accounting for the total number ofkey => value
pairs and attempts toreserve
this memory
dict_pre!{"hello" => 5, "world" => 13, "!" => 8}