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

如何让基于std::ranges::zip_view的C++排序代码正常运行?

问题解决思路与修正代码

核心错误分析

你的代码有两个关键问题导致无法运行:

  • 比较器类型不匹配:std::ranges::sort要求第二个参数是二元谓词(接受两个元素并返回布尔值),但你传入的std::ranges::lexicographical_compare是一个独立算法,需要两个范围作为输入,不能直接作为排序比较器。
  • zip_view排序的副作用:std::ranges::views::zip生成的视图元素是原容器的引用,排序时会直接交换indexes和values的元素,导致投影依赖的values数组在排序过程中被修改,破坏了排序依据的原始前缀序列。

修正方案(保留流水线投影+无容器复制)

我们可以通过先排序原始索引、再原地重排容器的方式解决问题,既保留投影的流水线写法,又不会复制原容器:

修正后的代码

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

int main()
{
    std::vector values={7,3,9,2,4,7};
    std::vector indexes={0,1,2,3,4,5};
    
    // 创建原始索引数组,记录每个元素的初始位置
    std::vector<std::size_t> original_idx(values.size());
    std::iota(original_idx.begin(), original_idx.end(), 0);

    // 基于原始values的反向前缀视图排序索引数组
    std::ranges::sort(original_idx,
        [&values](std::size_t a, std::size_t b) {
            // 保留流水线式的投影写法
            auto proj_a = values | std::ranges::views::take(a + 1) | std::ranges::views::reverse;
            auto proj_b = values | std::ranges::views::take(b + 1) | std::ranges::views::reverse;
            // 用字典序比较两个投影视图作为排序依据
            return std::ranges::lexicographical_compare(proj_a, proj_b);
        });

    // 根据排序后的索引,原地重排indexes和values(无容器复制)
    std::ranges::permute(indexes, original_idx);
    std::ranges::permute(values, original_idx);

    // 输出结果
    for (auto i : indexes) {
        for (int vi = 0; vi < i; ++vi) {
           std::cout << values[vi] << " ";
        }
        std::cout << std::endl;
    }
}

方案说明

  1. 原始索引数组:用std::iota生成0到容器长度-1的索引,确保排序依据是原始values数组的前缀,避免排序过程中修改values导致投影失效。
  2. 流水线投影保留:比较器中依然使用values | take(n+1) | reverse的流水线写法生成投影视图,完全符合你的需求。
  3. 原地重排:使用std::ranges::permute根据排序后的索引原地调整indexes和values的元素顺序,无需复制整个容器,内存开销极小。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 08:58:11