I happened upon what should've been a straightforward problem, described to me by a friend in C++, and tried to implement it in Rust.
The problem: given a set of pairs of strings, like ("one", "one"), ("two", "two")
join each pair over a :
and then join them all together over a ,
so the result is: "one:one,two:two"
Joining pairs was indeed straightforward:
let strings = set.iter().map(|&(a, b)| format!("{}:{}", a, b))
But connecting the iterator into a single string proved cumbersome:
let strings = set.iter().map(|&(a, b)| format!("{}:{}", a, b));
let result = strings.collect::<Vec<_>>().connect(",");
Having to build a real concrete vector in memory just to, basically, iterate over it again seems suboptimal. Yet it's the only way I could find in a standard library. Did I miss another?
My second attempt was to use itertools:
let result: String = strings.intersperse(",".to_string()).collect();
Even without dwelling on the ugly but necessary .to_string()
call this didn't work because a String knows how to construct itself from an iterator of &str
but doesn't know how to construct itself from other Strings. Is that a simple omission in the standard library or is it me missing some work around? Because this didn't work either:
let result: String = strings.intersperse(",".to_string()).map(|s|. s.to_str()).collect();
… as s
only lives within the closure and can't be to_str()
ed out of it.
Finally I've managed to do this by manually using fold()
:
let strings = set.iter().map(|&(a, b)| format!("{}:{}", a, b));
let result = strings.intersperse(",".to_string()).fold(String::new(), |res, s| res + &s);
But that looks way more involving than it should… Any advice? Thanks!