patternrustMinor
Transposing characters in a string
Viewed 0 times
characterstransposingstring
Problem
I want to create a function that takes a string and returns an array of versions of it in which always one pair of characters is transposed (swapped).
I came up with this:
Output is:
That result is what I want, it does:
I don't find the code super readable because of the string slicing going on. In C it would be a mere "pointer swap", but my Rust version looks a bit more involved.
Is there a better way to do what I want?
It is a fair assumption that this will only work correctly for ASCII strings.
I came up with this:
fn transposes(s: &str) -> Vec {
let mut vec = vec![];
let b = s.as_bytes();
for i in 1..b.len() {
let mut transpose = String::with_capacity(s.len());
transpose.push_str(&s[..i - 1]);
transpose.push(s.as_bytes()[i] as char);
transpose.push(s.as_bytes()[i - 1] as char);
transpose.push_str(&s[i + 1..]);
vec.push(transpose);
}
vec
}
fn main() {
let s = "maxi".to_owned();
println!("{:?}", transposes(&s));
}Output is:
["amxi", "mxai", "maix"]That result is what I want, it does:
- First swap
manda
- Then swap
aandx
- Then swap
iandx
I don't find the code super readable because of the string slicing going on. In C it would be a mere "pointer swap", but my Rust version looks a bit more involved.
Is there a better way to do what I want?
It is a fair assumption that this will only work correctly for ASCII strings.
Solution
- If it's just ASCII, treat it as a byte array all the way until the end.
Vechas aswapmethod and you can reconstruct aStringfrom the bytes.
- Use
mapandcollectinstead of allocating aVecand manuallypushing.
- There's no need to allocate a
Stringto pass to&str.
fn transposes(s: &str) -> Vec {
let bytes = s.as_bytes();
(1..bytes.len()).map(|i| {
let mut transpose = bytes.to_owned();
transpose.swap(i - 1, i);
String::from_utf8(transpose).expect("Invalid UTF-8")
}).collect()
}
fn main() {
println!("{:?}", transposes("maxi"));
}Even better, if your data is ASCII, encode that in the type system:
extern crate ascii;
use ascii::{AsciiStr, AsciiString};
fn transposes(s: &AsciiStr) -> Vec {
(1..s.len()).map(|i| {
let mut transpose = s.to_owned();
transpose.as_mut_slice().swap(i - 1, i);
transpose
}).collect()
}
fn main() {
let s = AsciiStr::from_ascii("maxi").expect("Not ASCII");
println!("{:?}", transposes(s));
}Note that the
transposes function can no longer fail due to invalid strings.Code Snippets
fn transposes(s: &str) -> Vec<String> {
let bytes = s.as_bytes();
(1..bytes.len()).map(|i| {
let mut transpose = bytes.to_owned();
transpose.swap(i - 1, i);
String::from_utf8(transpose).expect("Invalid UTF-8")
}).collect()
}
fn main() {
println!("{:?}", transposes("maxi"));
}extern crate ascii;
use ascii::{AsciiStr, AsciiString};
fn transposes(s: &AsciiStr) -> Vec<AsciiString> {
(1..s.len()).map(|i| {
let mut transpose = s.to_owned();
transpose.as_mut_slice().swap(i - 1, i);
transpose
}).collect()
}
fn main() {
let s = AsciiStr::from_ascii("maxi").expect("Not ASCII");
println!("{:?}", transposes(s));
}Context
StackExchange Code Review Q#155294, answer score: 4
Revisions (0)
No revisions yet.