4

This (playground):

let s = "Hello world!";
let splitted_string = s.split_terminator("").skip(1).collect::<Vec<&str>>();
println!("splitted_string: {:?}", splitted_string);

results in the following output:

splitted_string: ["H", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d", "!"]

How can I insert an a between each element and obtain something like this?

["H", "a", "e", "a", "l", "a", "l", "a", "o", "a", " ", "a", "w", "a", "o", "a", "r", "a", "l", "a", "d", "a", "!"]
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
manuel.menendez
  • 185
  • 3
  • 11
  • 2
    The `itertools` crate [has a function for this](https://docs.rs/itertools/0.8.0/itertools/trait.Itertools.html#method.intersperse), and there's also [an unstable `Iterator` method](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.intersperse). – Sven Marnach Aug 02 '21 at 15:01
  • [What's an idiomatic way to print an iterator separated by spaces in Rust?](https://stackoverflow.com/q/36941851/155423) – Shepmaster Aug 02 '21 at 15:36
  • [Alternative](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=2e8f79de2c6fc2499d41c5315ef3f2aa) – Ömer Erden Aug 02 '21 at 21:46
  • Same with my previous alternative but with new features: [Alternative](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=f9ae2b2422223fb6178ec1dbadacdcb8) – Ömer Erden Aug 02 '21 at 22:16

2 Answers2

5

There's already a good .flat_map() answer, but to give a slightly different approach for the sake of variety, we can shave that extra 'a' off the end by using .take():

fn main() {
    let s = "Hello world!";
    
    let interspersed = s.chars()
                        .flat_map(|c| [c, 'a'])
                        .take(s.len() * 2 - 1)
                        .collect::<String>();
                        
    println!("interspersed: {:?}", interspersed);
}

output:

interspersed: "Haealalaoa awaoaralada!"
Todd
  • 4,669
  • 1
  • 22
  • 30
4

It is still experimental, but iter::intersperse does exactly that.

From the doc example:

#![feature(iter_intersperse)]

let mut a = [0, 1, 2].iter().intersperse(&100);
assert_eq!(a.next(), Some(&0));   // The first element from `a`.
assert_eq!(a.next(), Some(&100)); // The separator.
assert_eq!(a.next(), Some(&1));   // The next element from `a`.
assert_eq!(a.next(), Some(&100)); // The separator.
assert_eq!(a.next(), Some(&2));   // The last element from `a`.
assert_eq!(a.next(), None);

In the meanwhile, the itertools::intersperse crate has the same functionality.

A solution that only uses the current stable standard library:

use std::iter;
fn main() {
    let s = "Hello world!";
    let result: Vec<char> = s
        .chars()
        .zip(iter::repeat('a'))
        .flat_map(|(a, sep)| vec![sep, a])
        .skip(1)
        .collect();
    println!("{:?}", result);
}

Results:

['H', 'a', 'e', 'a', 'l', 'a', 'l', 'a', 'o', 'a', ' ', 'a', 'w', 'a', 'o', 'a', 'r', 'a', 'l', 'a', 'd', 'a', '!']

Playground

Ömer Erden
  • 7,680
  • 5
  • 36
  • 45
Netwave
  • 40,134
  • 6
  • 50
  • 93
  • The currently proposed standard library solution suffers from the fence post problem adding an extra `'a'` at the end. You could solve this by essentially doing [what itertools does](https://docs.rs/itertools/0.10.1/src/itertools/intersperse.rs.html#75-87). – Fynn Becker Aug 02 '21 at 15:54
  • 1
    @FynnBecker, indeed. He changed it, fixed now. thanks for the heads up! – Netwave Aug 02 '21 at 16:56