I have a nested loop where I want to check if a certain condition holds on a table of usize values. However, the table may only be partially filled -- so it is actually a table of Option<usize> variables. When at least one of the values is missing, I do not consider the condition to be violated, and therefore want to continue on with the next set of values.
Currently I do it as follows:
for i in 0..n {
for j in 0..n {
for k in 0..n {
let v_ij = match table[i][j] {
None => { continue; },
Some(val) => { val }
};
let v_jk = match table[j][k] {
None => { continue; },
Some(val) => { val }
};
let res_left = match table[v_ij][k] {
None => { continue; },
Some(val) => { val }
};
let res_right = match table[i][v_jk] {
None => { continue; },
Some(val) => { val }
};
if res_left != res_right {
return false;
}
}
}
}
(For context: the computation is checking whether a partial magma is associative, but this is not important for the question.)
Is there an idiomatic way to replace all these matches? In Haskell, using the Maybe monad, I believe I could wrap this piece of code up into a do block, so that None values are automatically propagated. I tried using table[i][j].unwrap_or({continue;}) but this evaluates the continue greedily; using table[i][j].unwrap_or_else({continue;}) gives a syntax error.
In such a case, to limit repetition and to improve clarity, I would probably use a macro:
macro_rules! unwrap_or_continue {
($opt: expr) => {
match $opt {
Some(v) => v,
None => {continue;}
}
}
}
There is loop_unwrap crate that implement something similar but more complex.
Thus each of your test would be reduced:
for i in 0..n {
for j in 0..n {
for k in 0..n {
let v_ij = unwrap_or_continue!(table[i][j]);
let v_jk = unwrap_or_continue!(table[j][k]);
let res_left = unwrap_or_continue!(table[v_ij][k]);
let res_right = unwrap_or_continue!(table[i][v_jk]);
if res_left != res_right {
return false;
}
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With