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

如何用C++20/C++23 ranges库实现可交换的双层Zip视图?

解决方案:创建可支持排序的双层Zip视图

你的核心问题在于:之前通过transform返回的内层zip视图是临时视图类型,这类视图不满足swappable概念,因此无法被sort等算法操作。要解决这个问题,需要让视图的元素成为能同步修改底层数据的可交换实体,或者直接对底层可交换的元素视图进行排序。

方案一:直接对zip(v1, v2)视图排序(无需自定义类型)

std::ranges::views::zip(v1, v2)生成的视图元素是std::pair<std::array<int,2>&, std::array<int,2>&>,本身支持交换(交换时会同步修改v1和v2中对应的数组)。我们只需自定义比较逻辑,让排序依据双层Zip后的结构即可。

示例代码

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

// 打印双层Zip结构
void print_double_zip(const auto& v1, const auto& v2) {
    auto double_zip = std::ranges::views::zip(v1, v2)
                    | std::ranges::views::transform([](const auto& p) {
                          return std::ranges::views::zip(std::get<0>(p), std::get<1>(p));
                      });
    std::cout << "[";
    bool first = true;
    for (const auto& inner : double_zip) {
        if (!first) std::cout << ", ";
        first = false;
        std::cout << "[";
        bool inner_first = true;
        for (const auto& p : inner) {
            if (!inner_first) std::cout << ", ";
            inner_first = false;
            std::cout << "(" << p.first << ", " << p.second << ")";
        }
        std::cout << "]";
    }
    std::cout << "]\n";
}

int main() {
    std::vector<std::array<int, 2>> v1 = { {5, 6}, {1, 2}, {3, 4} };
    std::vector<std::array<int, 2>> v2 = { {11, 12}, {7, 8}, {9, 10} };

    std::cout << "排序前:\n";
    print_double_zip(v1, v2);

    // 对Zip视图排序,比较双层Zip的字典序
    auto zip_v = std::ranges::views::zip(v1, v2);
    std::ranges::sort(zip_v, [](const auto& lhs, const auto& rhs) {
        auto lhs_inner = std::ranges::views::zip(std::get<0>(lhs), std::get<1>(lhs));
        auto rhs_inner = std::ranges::views::zip(std::get<0>(rhs), std::get<1>(rhs));
        return std::ranges::lexicographical_compare(lhs_inner, rhs_inner);
    });

    std::cout << "排序后:\n";
    print_double_zip(v1, v2);

    return 0;
}

方案二:自定义代理对象,创建可直接排序的双层Zip视图

如果希望直接对双层Zip视图执行排序,可以自定义一个代理结构体,它持有对v1和v2数组的引用,支持交换和比较操作,同时能返回内层的Zip视图用于访问元素。

示例代码

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

// 代理结构体:持有两个数组的引用,支持交换和比较
struct ZipPairProxy {
    std::array<int, 2>& arr1;
    std::array<int, 2>& arr2;

    // 返回内层Zip视图,用于访问/修改元素
    auto inner_zip() const {
        return std::ranges::views::zip(arr1, arr2);
    }

    // 按双层Zip的字典序比较
    friend bool operator<(const ZipPairProxy& lhs, const ZipPairProxy& rhs) {
        return std::ranges::lexicographical_compare(lhs.inner_zip(), rhs.inner_zip());
    }

    // 交换代理,同步修改底层数组
    friend void swap(ZipPairProxy& lhs, ZipPairProxy& rhs) noexcept {
        using std::swap;
        swap(lhs.arr1, rhs.arr1);
        swap(lhs.arr2, rhs.arr2);
    }
};

// 打印双层Zip视图
void print_double_zip_view(const auto& view) {
    std::cout << "[";
    bool first = true;
    for (const auto& proxy : view) {
        if (!first) std::cout << ", ";
        first = false;
        std::cout << "[";
        bool inner_first = true;
        for (const auto& p : proxy.inner_zip()) {
            if (!inner_first) std::cout << ", ";
            inner_first = false;
            std::cout << "(" << p.first << ", " << p.second << ")";
        }
        std::cout << "]";
    }
    std::cout << "]\n";
}

int main() {
    std::vector<std::array<int, 2>> v1 = { {5, 6}, {1, 2}, {3, 4} };
    std::vector<std::array<int, 2>> v2 = { {11, 12}, {7, 8}, {9, 10} };

    // 创建可排序的双层Zip视图
    auto double_zip_view = std::ranges::views::zip(v1, v2)
                         | std::ranges::views::transform([](auto& p) -> ZipPairProxy {
                               return {std::get<0>(p), std::get<1>(p)};
                           });

    std::cout << "排序前:\n";
    print_double_zip_view(double_zip_view);

    // 直接对视图执行排序
    std::ranges::sort(double_zip_view);

    std::cout << "排序后:\n";
    print_double_zip_view(double_zip_view);

    // 修改视图中的元素(会同步修改v1和v2)
    auto first_proxy = *double_zip_view.begin();
    auto first_inner = *first_proxy.inner_zip().begin();
    first_inner.first = 100;
    first_inner.second = 200;
    std::cout << "修改后:\n";
    print_double_zip_view(double_zip_view);

    return 0;
}

原实现失效的原因

你之前的代码通过transform返回views::zip的结果,生成的是transform_view<zip_view<...>, ...>,其元素类型是视图对象而非可交换的实体。交换这类视图对象不会修改底层的v1和v2,且标准库视图通常不满足swappable概念,因此无法被sort等算法操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 20:06:59