2

I am trying swap two chars in a String. Here is My Code, I guess there must be a better way to do this.

pub fn swap(s: &String, from_idx: usize, to_idx: usize) -> String {
   let a = s.clone().chars().nth(from_idx).unwrap();
   let b = s.clone().chars().nth(to_idx).unwrap();
   let mut result = s.clone();
   result.replace_range(from_idx..from_idx + 1, &b.to_string());
   result.replace_range(to_idx..to_idx + 1, &a.to_string());
   return result;
}

Is there a better way, such as shorter syntax or better perfomance?

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
En Xie
  • 510
  • 4
  • 19
  • Although not a duplicate, you might also find more information at [this answer](https://stackoverflow.com/questions/27895150) – Filipe Rodrigues Dec 08 '21 at 13:06
  • “Is there a better way” Yes. Swapping Unicode Scalar Values makes little to no sense. You probably shouldn't be using a string in the first place. – mcarton Dec 08 '21 at 14:31
  • Note also that the code in question is swapping bytes, not chars. So it will panic if characters on the provided indices are not ASCII - https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=d78bfbfdc49a91bffb08a5ae2854b68b. – Cerberus Dec 08 '21 at 15:55

1 Answers1

2

My approach would be:

pub fn swap(s: &str, from_idx: usize, to_idx: usize) -> String {
   // create a Vec of all characters
   let mut chars: Vec<_> = s.chars().collect();
   // swap the characters in the Vec
   chars.swap(from_idx, to_idx);
   // convert Vec back to String
   chars.into_iter().collect()
}
Akida
  • 1,076
  • 5
  • 16
  • thank you, Now I know Vec has the swap method can do the trick – En Xie Dec 08 '21 at 13:02
  • Also see [Why is it discouraged to accept a reference to a String (&String), Vec (&Vec), or Box (&Box) as a function argument?](https://stackoverflow.com/questions/40006219) – Filipe Rodrigues Dec 08 '21 at 13:02
  • 1
    This will seem to work on simple strings with simple Unicode, but not in general. Swapping Unicode Scalar Value makes no sense. There's almost no correct use for `str::chars`. – mcarton Dec 08 '21 at 14:33
  • @mcarton can you point out a case where this wouldn’t work? – hackape Dec 09 '21 at 00:36
  • 2
    @hackape swapping characters 0 and 2 in this string: `èa` (yes it contains three characters) will give `àe` (probably not what you expect) – Jmb Dec 09 '21 at 08:26
  • 2
    Here's a [playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=08eaf850f1dd0431911065ff007494cd) that illustrates my previous comment. – Jmb Dec 09 '21 at 08:52