Есть ли способ объединить два итератора в один и тот же Vec? - PullRequest
1 голос
/ 14 марта 2019

У меня есть два итератора, которые в итоге сливаются в один и тот же Vec, но мне нужно выполнить фильтр конечного результата перед слиянием.Например:

let a = vec![1, 2, 3, 4].into_iter().map(|x| x * 2);
let b = vec![0, 3, 5, 6, 7].into_iter().map(|x| x * 3);
let c = a + b;
assert_eq!(
    c.filter(|&x| x > 5).collect::<Vec<u8>>(),
    vec![6, 8, 9, 15, 18, 21]
);

Я мог бы сделать что-то вроде этого:

let mut a = vec![1, 2, 3, 4]
    .into_iter()
    .map(|x| x * 2)
    .collect::<Vec<u8>>();
let b = vec![0, 3, 5, 6, 7]
    .into_iter()
    .map(|x| x * 3)
    .collect::<Vec<u8>>();
a.extend(b);
assert_eq!(
    a.into_iter().filter(|&x| x > 5).collect::<Vec<u8>>(),
    vec![6, 8, 9, 15, 18, 21]
);

Но дополнительное распределение снижает производительность в моем случае (да, я проверял!)

Ответы [ 2 ]

8 голосов
/ 14 марта 2019

Вы ищете Iterator::chain

let a = vec![1, 2, 3, 4].into_iter().map(|x| x * 2);
let b = vec![0, 3, 5, 6, 7].into_iter().map(|x| x * 3);
let c = a.chain(b);
assert_eq!(
    c.filter(|&x| x > 5).collect::<Vec<u8>>(),
    vec![6, 8, 9, 15, 18, 21]
);
1 голос
/ 14 марта 2019

В качестве альтернативы вы можете использовать extend():

let a = (0..500000).map(|x| x * 2);
let b = (0..500000).map(|x| x * 3);
let mut c = Vec::with_capacity(a.size_hint().1.unwrap() + b.size_hint().1.unwrap());
c.extend(a);
c.extend(b);

Это требует, чтобы вы явно использовали with_capacity(), что chain() и collect() сделали бы для вас. В ситуации, когда a уже построен, вместо построения временного вектора подойдет extend().

В этом случае я не нашел никакой разницы между chain() и extend ( отметка )

Это не делает фильтрацию. Себастьян Редл

Правильно! Исправление этой ошибки показывает, что по какой-то причине LLVM больше не оптимизирует chain(). Версия с extend:

let a = (0..500000).map(|x| x * 2);
let b = (0..500000).map(|x| x * 3);
let mut c = Vec::with_capacity(a.size_hint().1.unwrap() + b.size_hint().1.unwrap());
c.extend(a.filter(|&x| x > 5));
c.extend(b.filter(|&x| x > 5));

В два раза быстрее, чем версия с chain (это то, что я ожидал в первую очередь):

let a = (0..500000).map(|x| x * 2);
let b = (0..500000).map(|x| x * 3);
let _c: Vec<_> = a.chain(b).filter(|&x| x > 5).collect();

( тест )

...