You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Rust中对已排序Vec实现`uniq -c`功能并遍历计数与值

实现有序Vec的连续重复元素计数迭代器(支持正向/反向遍历)

方案1:先统计后遍历(简单直观)

如果你的Vec是有序的(连续重复元素相邻),可以先一次性统计所有连续元素的出现次数,再通过Vec的迭代器实现正向/反向遍历:

fn main() {
    let a = vec![1, 1, 2, 3, 3, 3];
    
    // 统计连续元素的计数
    let counts = count_consecutive(a.iter());
    
    // 正向遍历
    for (&value, count) in &counts {
        println!("{value}\t{count}");
        // 输出:
        // 1	2
        // 2	1
        // 3	3
    }
    
    // 反向遍历
    for (&value, count) in counts.iter().rev() {
        println!("{value}\t{count}");
        // 输出:
        // 3	3
        // 2	1
        // 1	2
    }
}

// 统计连续重复元素的函数,接收迭代器返回值与计数的Vec
fn count_consecutive<I>(mut iter: I) -> Vec<(I::Item, usize)>
where
    I: Iterator,
    I::Item: PartialEq,
{
    let mut result = Vec::new();
    
    // 取出第一个元素作为初始值
    let Some(mut current_val) = iter.next() else {
        return result;
    };
    let mut current_count = 1;
    
    for val in iter {
        if val == current_val {
            current_count += 1;
        } else {
            result.push((current_val, current_count));
            current_val = val;
            current_count = 1;
        }
    }
    
    // 加入最后一组元素
    result.push((current_val, current_count));
    
    result
}

这个方案的优点是简单易懂,适合大部分场景。统计完成后,正向遍历直接用Vec的迭代器,反向遍历调用rev()即可。


方案2:自定义惰性迭代器(更贴合伪代码写法)

如果想更贴近你伪代码里直接调用a.iter1()、a.iter2().rev()的形式,可以给Vec实现扩展方法,自定义支持正向/反向的连续计数迭代器:

use std::iter::DoubleEndedIterator;

// 定义扩展trait,给Vec添加连续计数迭代器方法
trait ConsecutiveIterExt<T> {
    // 正向连续元素计数迭代器
    fn iter_consecutive(&self) -> ConsecutiveCounter<std::slice::Iter<'_, T>>;
    // 反向连续元素计数迭代器(从末尾开始统计)
    fn iter_consecutive_rev(&self) -> ReverseConsecutiveCounter<std::slice::Iter<'_, T>>;
}

// 为Vec实现扩展trait
impl<T: PartialEq> ConsecutiveIterExt<T> for Vec<T> {
    fn iter_consecutive(&self) -> ConsecutiveCounter<std::slice::Iter<'_, T>> {
        ConsecutiveCounter::new(self.iter())
    }
    
    fn iter_consecutive_rev(&self) -> ReverseConsecutiveCounter<std::slice::Iter<'_, T>> {
        ReverseConsecutiveCounter::new(self.iter().rev())
    }
}

// 正向连续计数迭代器结构体
struct ConsecutiveCounter<I> {
    iter: I,
    current_val: Option<I::Item>,
    current_count: usize,
}

impl<I> ConsecutiveCounter<I>
where
    I: Iterator,
    I::Item: PartialEq,
{
    fn new(mut iter: I) -> Self {
        let current_val = iter.next();
        let current_count = current_val.is_some() as usize;
        Self {
            iter,
            current_val,
            current_count,
        }
    }
}

// 实现Iterator trait
impl<I> Iterator for ConsecutiveCounter<I>
where
    I: Iterator,
    I::Item: PartialEq,
{
    type Item = (I::Item, usize);
    
    fn next(&mut self) -> Option<Self::Item> {
        let Some(mut current_val) = self.current_val.take() else {
            return None;
        };
        let mut current_count = self.current_count;
        
        while let Some(val) = self.iter.next() {
            if val == current_val {
                current_count += 1;
            } else {
                self.current_val = Some(val);
                self.current_count = 1;
                break;
            }
        }
        
        Some((current_val, current_count))
    }
}

// 反向连续计数迭代器结构体
struct ReverseConsecutiveCounter<I> {
    iter: I,
    current_val: Option<I::Item>,
    current_count: usize,
}

impl<I> ReverseConsecutiveCounter<I>
where
    I: Iterator,
    I::Item: PartialEq,
{
    fn new(mut iter: I) -> Self {
        let current_val = iter.next();
        let current_count = current_val.is_some() as usize;
        Self {
            iter,
            current_val,
            current_count,
        }
    }
}

// 实现Iterator trait
impl<I> Iterator for ReverseConsecutiveCounter<I>
where
    I: Iterator,
    I::Item: PartialEq,
{
    type Item = (I::Item, usize);
    
    fn next(&mut self) -> Option<Self::Item> {
        let Some(mut current_val) = self.current_val.take() else {
            return None;
        };
        let mut current_count = self.current_count;
        
        while let Some(val) = self.iter.next() {
            if val == current_val {
                current_count += 1;
            } else {
                self.current_val = Some(val);
                self.current_count = 1;
                break;
            }
        }
        
        Some((current_val, current_count))
    }
}

fn main() {
    let a = vec![1,1,2,3,3,3];
    
    for (&value, count) in a.iter_consecutive(){
        println!("{value}\t{count}");
        // 输出:
        // 1	2
        // 2	1
        // 3	3
    }
    
    for (&value, count) in a.iter_consecutive_rev(){
        println!("{value}\t{count}");
        // 输出:
        // 3	3
        // 2	1
        // 1	2
    }
}

这种方式是惰性迭代,不会一次性把所有统计结果存入内存,适合处理大体积的Vec。

注意事项

两种方案都依赖原Vec是有序的(即相同元素是连续排列的),如果Vec无序,需要先调用sort()排序后再使用这些方法。

内容的提问来源于stack exchange,提问作者Moold

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 23:20:06