Transposing characters in a string 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:

fn transposes(s: &amp;str) -&gt; Vec&lt;String&gt; {
    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(&amp;s[..i - 1]);
        transpose.push(s.as_bytes()[i] as char);
        transpose.push(s.as_bytes()[i - 1] as char);
        transpose.push_str(&amp;s[i + 1..]);

        vec.push(transpose);
    }

    vec
}

fn main() {
    let s = "maxi".to_owned();
    println!("{:?}", transposes(&amp;s));   
}


Output is:

["amxi", "mxai", "maix"]


That result is what I want, it does:


First swap m and a
Then swap a and x
Then swap i and x


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.
If it's just ASCII, treat it as a byte array all the way until the end. Vec has a swap method and you can reconstruct a String from the bytes.
Use map and collect instead of allocating a Vec and manually pushing.
There's no need to allocate a String to pass to &amp;str.




fn transposes(s: &amp;str) -&gt; Vec&lt;String&gt; {
    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: &amp;AsciiStr) -&gt; Vec&lt;AsciiString&gt; {
    (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.