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

如何在std::unique处理vector后更新元素的新索引?

问题描述

现有一个函数,参数impObj指向vector<MyClass>类型容器myVec中的某个元素索引。调用std::unique去除连续重复元素并删除冗余元素后,需要更新impObj,使其指向原MyClass实例(或原连续重复组中的对应实例)在处理后vector中的新索引。

现有初始函数代码:

void RemoveSequentialDuplicates(std::vector<MyClass>& myVec, int& impObj)
{
    auto itrLast = std::unique(myVec.begin(), myVec.end(), [](const MyClass& first, const MyClass& second) -> bool {
       return first == second;
    });
    myVec.erase(itrLast, myVec.end());
}

需求示例

  • 输入1:[A, A, B, B, D, A],impObj = 5
    输出1:[A, B, D, A],impObj = 3
  • 输入2:[A, B, B, B, A, A, C],impObj = 2
    输出2:[A, B, A, C],impObj = 1

注:不强制使用std::unique,需保持元素顺序不变。当前已有一种实现方案,但希望找到更优方式:

void RemoveSequentialDuplicates(std::vector<MyClass>& myVec, int& index)
{
    int leftIndex = 0, rightIndex = 1;
    auto itrLast = std::unique(myVec.begin(), myVec.end(), [&leftIndex, &rightIndex, &impObj](const MyClass& first, const MyClass& second) -> bool {
        bool equals = false;
        if (first == second)
            equals = true;
        else
            leftIndex++;

        if(impObj == rightIndex)
            impObj = leftIndex;

        rightIndex++;
        return equals;
    });
    myVec.erase(itrLast, myVec.end());
}
更优实现方案

原方案的核心问题是在std::unique的lambda中维护多个状态变量,逻辑耦合度高,边界场景容易出错。以下两种方案将索引更新与去重逻辑解耦,可读性和稳定性更优:

方案一:预统计偏移量后更新索引

先计算原索引位置前被移除的连续重复元素数量,再基于这个偏移量更新目标索引:

void RemoveSequentialDuplicates(std::vector<MyClass>& myVec, int& impObj)
{
    if (myVec.empty())
    {
        impObj = -1;
        return;
    }

    // 统计原impObj位置前,会被std::unique移除的元素数量
    int removedCount = 0;
    for (int i = 1; i <= impObj; ++i)
    {
        if (myVec[i] == myVec[i-1])
        {
            removedCount++;
        }
    }

    // 执行去重操作
    auto last = std::unique(myVec.begin(), myVec.end());
    myVec.erase(last, myVec.end());

    // 更新索引:原索引减去被删除的元素数量
    impObj -= removedCount;
}

该方案逻辑清晰,将索引计算与去重操作分离,时间复杂度保持O(n),且避免了lambda内的状态维护。

方案二:手动遍历构建新容器并跟踪索引

完全手动控制去重过程,同时同步更新目标索引,逻辑直观且边界场景处理更周全:

void RemoveSequentialDuplicates(std::vector<MyClass>& myVec, int& impObj)
{
    if (myVec.empty())
    {
        impObj = -1;
        return;
    }

    std::vector<MyClass> newVec;
    newVec.reserve(myVec.size()); // 预分配内存,减少扩容开销
    newVec.push_back(myVec[0]);

    int newIndex = 0;
    bool indexUpdated = false;

    for (size_t i = 1; i < myVec.size(); ++i)
    {
        if (myVec[i] != newVec.back())
        {
            newVec.push_back(myVec[i]);
            newIndex++;
        }

        // 遍历到原目标索引时,记录对应的新索引
        if (!indexUpdated && static_cast<int>(i) == impObj)
        {
            impObj = newIndex;
            indexUpdated = true;
        }
    }

    // 处理原索引为0的特殊情况
    if (!indexUpdated && impObj == 0)
    {
        impObj = 0;
    }

    myVec.swap(newVec); // 交换容器,避免大规模拷贝
}

该方案无需依赖std::unique,手动处理逻辑更透明,swap操作的性能开销极低,同时能覆盖所有边界场景(如容器为空、目标索引为第一个元素等)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 23:25:25