Reputation: 31
I want to be able to provide vectors as arguments from an array of vectors to a macro iproduct!, which accepts varying numbers of arguments (all arguments must be Iterator element type).
Most important is the possibility of providing arrays with different lengths.
It seems that the method is called "Variadic function", which seems it is not yet implemented on Rust. Please, let me know your constructive comments. Thank you!
This is the idea, but it will not work as I intend.
// main.rs
use itertools::iproduct;
fn main() {
let arr = [vec![1,2,3],vec![0,1,2]];
let mut result = Vec::new();
for tupl in iproduct!(arr) {
result.push(tupl);
};
println!("{:?}", result)
}
// current output: [[1, 2, 3], [0, 1, 2]]
// expected output: [[1,0],[1,1],[1,2],[2,0],[2,1],[2,2],[3,0],[3,1],[3,2]]
So far, this works well, but it is static depending on the number of arguments and only for strings. I am forced to write several different combinations and still would be covering a few cases.
use itertools::iproduct;
type TS2 = (String,String);
type TS3 = (String,String,String);
pub fn cartesian_2vec(l1: Vec<String>, l2: Vec<String>) -> Vec<TS2> {
let mut collector = Vec::new();
for tupl in iproduct!(l1,l2) {
collector.push(tupl);
};
collector
}
pub fn cartesian_3vec(l1: Vec<String>, l2: Vec<String>, l3: Vec<String>) -> Vec<TS3> {
let mut collector = Vec::new();
for tupl in iproduct!(l1,l2,l3) {
collector.push(tupl);
};
collector
}
fn main() {
let list1 = vec![String::from('1'),String::from('2'),String::from('3')];
let list2 = vec![String::from('a'),String::from('b')];
println!("{:?}", cartesian_2vec(list1,list2))
}
// [("1", "a"), ("1", "b"), ("2", "a"), ("2", "b"), ("3", "a"), ("3", "b")]
Upvotes: 2
Views: 730
Reputation: 22476
Variadic functions don't exist in Rust. Instead, they are usually modelled with macros:
use itertools::iproduct;
macro_rules! cartesian_vecs {
($($l:expr),+) => {{
let mut collector = Vec::new();
for tupl in iproduct!($($l),+) {
collector.push(tupl);
}
collector
}};
}
fn main() {
let list1 = vec![String::from('1'), String::from('2'), String::from('3')];
let list2 = vec![String::from('a'), String::from('b')];
println!("{:?}", cartesian_vecs!(list1, list2));
}
[("1", "a"), ("1", "b"), ("2", "a"), ("2", "b"), ("3", "a"), ("3", "b")]
Or the even shorter version:
use itertools::iproduct;
macro_rules! cartesian_vecs {
($($l:expr),+) => {{
iproduct!($($l),+).collect::<Vec<_>>()
}};
}
fn main() {
let list1 = vec![String::from('1'), String::from('2'), String::from('3')];
let list2 = vec![String::from('a'), String::from('b')];
println!("{:?}", cartesian_vecs!(list1, list2));
}
[("1", "a"), ("1", "b"), ("2", "a"), ("2", "b"), ("3", "a"), ("3", "b")]
Upvotes: 1