Can this clone() be avoided?

I needed to find the unique count of each item in a list, but the only way I could get it to work was to clone the list inside a for loop, which is something I want to learn how to avoid. Simplified example:

fn main() {
    let v: Vec<i32> = vec![1, 2, 2, 3, 4, 4, 5];

    for i in v.clone() {
        let _count = v.clone().into_iter().filter(|j| *j == i).count();
    }
}

Can the inner clone be avoided while keeping the logic intact? (and without just using something that clones under-the-hood).

You can avoid both clones actually:

fn main() {
    let v: Vec<i32> = vec![1, 2, 2, 3, 4, 4, 5];

    for i in v.iter() {
        let _count = v.iter().filter(|j| *j == i).count();
    }
}

We should note that the time complexity of this solution is not good.

The textbook solution would use a map<item, count>.

2 Likes

Are you suggesting using a keyed map collection, or the map method of the iterator?

Of course a collection. The map method has the exact same complexity as a regular loop over the iterator, it's not magic.

The archetypical counter is

let mut map = HashMap::new();

for &i in &v {
    *map.entry(i).or_insert(0) += 1;
}

Furthermore, your example suggests that your vector is pre-sorted. If, and only if, that is the case, you can avoid the allocation of the map as well:

let mut slice = v.as_slice();    

while let Some(first) = slice.get(0) {
    let count = slice.iter()
                     .position(|v| v != first)
                     .unwrap_or(slice.len());

    slice = &slice[count..];

    println!("{first} => {count}");
}
4 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.