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

基于std::ranges实现排序数组最长重复序列保留及N扩展方案问询

问题描述

给定已排序数组,需要仅保留其中重复值的最长连续序列;同时希望将功能参数化,支持保留长度排名前N的重复序列。目前已有一段实现代码,询问是否可以通过std::ranges/views/projections实现更简洁的方案。

现有实现代码

#include <iostream>
#include <vector>
#include <algorithm>

auto keep_longest_sequences(auto first, auto last)
{
    auto dest_init = first;
    auto dest = first;

    decltype(std::distance(first, last)) max_range_size = 0;

    while (first != last) {
        auto it_next_val = std::upper_bound(first, last, *first);
        auto size = std::distance(first, it_next_val);

        if (size > max_range_size) {
            max_range_size = size;
            dest = dest_init;
            std::copy(first, it_next_val, dest);
            dest += size;
        }
        else if (size == max_range_size) {
            std::copy(first, it_next_val, dest);
            dest += size;
        }
        first = it_next_val;
    }

    return dest;
}

int main() {
    std::vector<int> v = { 1, 1, 1, 2, 2, 2, 2, 3, 3, 4, 4, 5, 6, 6, 6, 7, 7, 7, 7 };
    
    v.erase(keep_longest_sequences(v.begin(), v.end()), v.end());

    for (auto vi : v) {
            std::cout << vi << " ";
    }
}

预期结果

仅保留最长序列时输出:

2 2 2 2 7 7 7 7

支持保留前2长的序列时输出:

1 1 1 2 2 2 2 6 6 6 7 7 7 7


基于std::ranges的简洁实现

1. 仅保留最长连续重复序列的版本

利用C++20的std::ranges组件,通过分组、筛选、展平的声明式写法实现,代码更简洁直观:

#include <iostream>
#include <vector>
#include <ranges>
#include <algorithm>

int main() {
    std::vector<int> v = {1,1,1,2,2,2,2,3,3,4,4,5,6,6,6,7,7,7,7};

    // 1. 将连续重复元素分组
    auto grouped = v | std::views::chunk_by([](int a, int b){ return a == b; });

    // 2. 计算所有分组的长度,找出最大值
    auto lengths = grouped | std::views::transform([](auto&& r){ return std::ranges::distance(r); });
    const auto max_len = *std::ranges::max_element(lengths);

    // 3. 筛选长度等于最大值的分组,再展平为一维序列
    auto result = grouped | std::views::filter([max_len](auto&& r){ return std::ranges::distance(r) == max_len; })
                          | std::views::join;

    // 输出结果
    for (int num : result) {
        std::cout << num << " ";
    }

    // 若要修改原容器:
    // std::ranges::copy(result, v.begin());
    // v.erase(std::ranges::next(v.begin(), std::ranges::distance(result)), v.end());
}

2. 参数化支持保留前N长序列的版本

通过收集分组信息、排序长度阈值、筛选符合条件的分组,实现可配置的前N长序列保留功能:

#include <iostream>
#include <vector>
#include <ranges>
#include <algorithm>

template <std::ranges::forward_range R>
auto keep_top_n_longest_sequences(R&& r, size_t top_n) {
    // 1. 分组并存储每组的长度与对应子序列
    std::vector<std::pair<size_t, std::ranges::subrange<std::ranges::iterator_t<R>>>> groups;
    for (auto&& chunk : r | std::views::chunk_by([](auto a, auto b){ return a == b; })) {
        groups.emplace_back(std::ranges::distance(chunk), chunk);
    }

    if (groups.empty()) return std::views::empty<typename R::value_type>();

    // 2. 提取所有分组长度并降序排序,获取第top_n长的阈值(兼容并列情况)
    std::vector<size_t> lengths;
    std::ranges::transform(groups, std::back_inserter(lengths), [](auto& p){ return p.first; });
    std::ranges::sort(lengths, std::greater<>());

    top_n = std::min(top_n, lengths.size());
    const auto threshold = lengths[top_n - 1];

    // 3. 筛选长度不小于阈值的分组,展平为结果序列
    auto filtered_groups = groups | std::views::filter([threshold](auto& p){ return p.first >= threshold; })
                                  | std::views::transform([](auto& p){ return p.second; });

    return filtered_groups | std::views::join;
}

int main() {
    std::vector<int> v = {1,1,1,2,2,2,2,3,3,4,4,5,6,6,6,7,7,7,7};

    // 保留前2长的连续重复序列
    auto result = keep_top_n_longest_sequences(v, 2);

    for (int num : result) {
        std::cout << num << " ";
    }
}

实现说明

  • std::views::chunk_by:专门用于已排序序列的连续重复元素分组,是核心工具。
  • std::views::transform/filter:实现分组信息转换与筛选逻辑,代码可读性更强。
  • std::views::join:将筛选后的多组序列展平为一维,直接输出或写入容器。
  • 参数化版本通过长度排序获取阈值,自动兼容并列情况(比如多个序列长度同为第N长时,全部保留)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 08:07:49