0

I am writing a sieve of Eratosthenes, for this you want to start a vector of booleans with odd indices true and even indices false. Currently my code for getting that is:

let mut is_prime: Vec<bool> = vec![true; capacity];
is_prime.iter_mut().step_by(2).for_each(|m| *m = false);

However, I am trying to find a way of constructing the vector with this alternating true false sequence. Any help is appreciated, thanks.

Note

I know this won't have a massive impact on performance in this case, I but I thought it was an interesting problem and suspect there may be cases where it would make a difference.

Pioneer_11
  • 670
  • 4
  • 19
  • Interestingly your version comes out on top performance wise in a simple benchmark I came up with. – cafce25 Apr 04 '23 at 20:02
  • @cafce25 I did not expect that, are you comping with or without optimisation? The best explanation I can think of is either that rustc is able to optimise my implementation but not the others or that the iterator either does not know it's length or that length is not used to allocate the correct amount of memory. – Pioneer_11 Apr 05 '23 at 05:21
  • Unoptimized your code is already ahead by a factor of ~4 vs the `cycle` and ~3 vs the `repeat` versions below, optimized that advantage climbs to ~8x vs the `cycle` and drops to only ~2.5x vs the `repeat` variant. Here is the code I used on a [Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=435b77905f8ad8a10e73fd898ea2689d) – cafce25 Apr 05 '23 at 05:37
  • I'm still pretty inexperienced with rust so some of your code is unfamiliar to me. I'll need to read up on some things before I can say anything intelligent on this but I'll let you know if I figure it out or down the line. Thanks for your help, and if you happen to have a brainwave please let me know. I'd love to know what's going on here. – Pioneer_11 Apr 05 '23 at 06:23
  • @cafce25 I've tried to pre-allocate the output with `Vec::with_capacity` and then fill the result with `Vec::extend` and the pre-allocating versions are actually slightly _slower_ than the straight `repeat` or `cycle` versions, so it looks like allocation is not the cause of the slowdown ([playground](https://play.rust-lang.org/?version=stable&mode=release&edition=2021&gist=dec91f9d5ee7a17dc0702a4f0d7c428a)). – Jmb Apr 05 '23 at 07:14

2 Answers2

6

You can combine a few iterator utilities to do this efficiently and ergonomically:

let mut is_prime: Vec<_> = std::iter::repeat([true, false])
    .flatten()
    .take(capacity)
    .collect();

Note the iterator exactly knows its length, which allows collect to build a vector with enough capacity allocated in advance.

cdhowie
  • 158,093
  • 24
  • 286
  • 300
5

You can do it with cycle, take and collect:

let mut sieve: Vec<_> = [ false, true ].into_iter().cycle().take (capacity).collect();

Playground

Jmb
  • 18,893
  • 2
  • 28
  • 55