3

Given a &[u32] I want to filter out the number 0. This could be any number or any other rule or condition.

Here are a few versions that work, but I feel like this could be done simpler:

fn test(factors: &[u32]) {
    let factors1 = factors
        .iter()
        .map(|&x| x as u32)
        .filter(|x| *x != 0)
        .collect::<Vec<u32>>();

    let factors1 = factors
        .iter()
        .map(|&x| x as u32)
        .filter(|&x| x != 0)
        .collect::<Vec<u32>>();

    let factors2 = factors
        .iter()
        .filter(|x| **x != 0)
        .collect::<Vec<&u32>>();

    let factors3 = factors
        .iter()
        .filter(|&&x| x != 0)
        .collect::<Vec<&u32>>();
}

I was expecting something simpler like this (which doesn't work):

let factors4 = factors.iter().filter(|x| x != 0).collect();

Things that would be helpful are:

  • Is it possible to clone or convert a &u32 to u32?
  • Is there a way to clone a &[u32] to [u32]?
pretzelhammer
  • 13,874
  • 15
  • 47
  • 98
xx1xx
  • 1,834
  • 17
  • 16
  • "Is there a way to clone a &[u32] to [u32]?" a slice can't be build like this you need a reference somewhere – Stargateur Nov 04 '19 at 01:44
  • @Stargateur **&[u32]** = a reference to a *u32* array? Surely there must be a way to create a new u32 array that has the values (not a reference) to the elements? – xx1xx Nov 04 '19 at 04:42
  • 2
    as I said `[u32]` is a slice NOT an array. An array is `[u32; 42]`. Be sure to use exact term. You can construct an array, but not a slice (without the reference), you can construct a reference to a slice but not a slice alone. I give it to you slice and slice can refer to `&[u32]` or `[u32]` but you can construct a `&[u32]` but not a `[u32]` – Stargateur Nov 04 '19 at 05:28
  • 1
    You may [construct a `Vec` using the `to_vec` method on slices](https://stackoverflow.com/questions/47980023/how-to-convert-from-u8-to-vecu8). – trent Nov 04 '19 at 13:00

2 Answers2

2

There’s Iterator.copied(), at least?

let factors4: Vec<u32> = factors
    .iter()
    .copied()
    .filter(|&x| x != 0)
    .collect();
Ry-
  • 218,210
  • 55
  • 464
  • 476
  • Thanks! **copied** seems like a good choice: _This is useful when you have an iterator over &T, but you need an iterator over T._ – xx1xx Nov 04 '19 at 04:37
  • why do we still have to use the reference symbol in _filter_ `.filter(|&x| x != 0)` ? – xx1xx Nov 04 '19 at 04:47
  • 1
    @xx1xx: Because `filter` can’t take ownership of the values in the iterator it’s testing. It still has to pass them through. – Ry- Nov 04 '19 at 05:57
2

You may use filter_map to filter and map in a single step.

fn make_vec_of_nonzero(factors: &[u32]) -> Vec<u32> {
    factors
        .iter()
        .filter_map(|&x| if x == 0 { None } else { Some(x) })
        .collect()
}
xx1xx
  • 1,834
  • 17
  • 16
trent
  • 25,033
  • 7
  • 51
  • 90