• C++ 用sort和unique实现数据的去重


    1. 应用场景

    有自定义的数据类型Point,存放在std::vector中,想对其进行去重的操作。
    Point.h

    struct Point
    {
        double X, Y, Z;
        Point() {};
        Point(double x,double y,double z)
            :X(x),Y(y),Z(z){}
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    main.cpp

    #include 
    #include 
    #include "Point.h"
    #include 
    
    using namespace std;
    
    int main()
    {
        vector<Point> v;
        Point p0(0, 0, 0);
        Point p1(1, 2, 3);
        Point p2(0, 0, 0);
        Point p3(0, 0, 0);
        Point p4(1, 0, 5);
        Point p5(1, 2, 3);
        v.push_back(p0);
        v.push_back(p1);
        v.push_back(p2);
        v.push_back(p3);
        v.push_back(p4);
        v.push_back(p5);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    1. std::sort

    将指定范围内的元素按升序方式进行排序。
    有两种使用方式:

    • Point实现操作符重载:<
    • 使用lambda表达式

    1.1 方式1:操作符重载<

    struct Point
    {
        double X, Y, Z;
        Point() {};
        Point(double x,double y,double z)
            :X(x),Y(y),Z(z){}
    	// 依次比较x,y,z坐标
        bool operator<(const Point& other) const
        {
            if (this->X < other.X)
                return true;
            else if (this->X == other.X)
            {
                if (this->Y < other.Y)
                    return true;
                else if (this->Y == other.Y)
                {
                    if (this->Z < other.Z)
                        return true;
                }
            }
            return false;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    // 调用已实现的<的操作符重载
    ::sort(v.begin(), v.end());
    
    • 1
    • 2

    最后排序的结构为:
    在这里插入图片描述

    1.2 方式2:使用lambda

    // 使用lambda手动指定比较规则:根据Z值,按从大到小排列
    ::sort(v.begin(), v.end(), [](Point a, Point b)
            {
                if (a.Z>b.Z)
                    return true;
                return false;
            });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    输出结果为:
    在这里插入图片描述

    2. std::unique

    对指定范围内的元素进行去重操作,实际逻辑是:用下一个不重复的元素替换重复元素。
    就因为这一点,所以在使用std::unique的时候,需要先对元素进行排序。
    我们先来试一下不排序的结果:

    vector<int> x;
        x.push_back(0);
        x.push_back(0);
        x.push_back(1);
        x.push_back(1);
        x.push_back(0);
        x.push_back(0);
        x.push_back(5);
        ::unique(x.begin(),x.end());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    运行结果为:
    ![在这里插入图片描述](https://img-blog.csdnimg.cn/dd1e1d3d63544521955e2580df962e89.png
    显然我们并没有得到正确的结果。进行排序:

    vector<int> x;
        x.push_back(0);
        x.push_back(0);
        x.push_back(1);
        x.push_back(1);
        x.push_back(0);
        x.push_back(0);
        x.push_back(5);
        ::sort(x.begin(), x.end());
        ::unique(x.begin(),x.end());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    结果为:在这里插入图片描述
    unique函数的返回值为iterator,即从begin到it之间的元素就是没有重复的元素,而it之后的元素都是无效值。

    vector<int>::iterator it = ::unique(x.begin(),x.end());
    
    • 1

    2.1 方式1:操作符重载==

    struct Point
    {
        double X, Y, Z;
    
        Point() {};
        Point(double x,double y,double z)
            :X(x),Y(y),Z(z){}
    
        bool operator==(const Point& other) const
        {
            return this->X == other.X && this->Y == other.Y && this->Z == other.Z;
        }
    
        bool operator<(const Point& other) const
        {
            if (this->operator==(other))
                return false;
    
            if (this->X < other.X)
                return true;
            else if (this->X == other.X)
            {
                if (this->Y < other.Y)
                    return true;
                else if (this->Y == other.Y)
                {
                    if (this->Z < other.Z)
                        return true;
                }
            }
            return false;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    调用:

        vector<Point> v;
    
        Point p0(0, 0, 0);
        Point p1(1, 2, 3);
        Point p2(0, 0, 0);
        Point p3(0, 0, 0);
        Point p4(1, 0, 5);
        Point p5(1, 2, 3);
    
        v.push_back(p0);
        v.push_back(p1);
        v.push_back(p2);
        v.push_back(p3);
        v.push_back(p4);
        v.push_back(p5);
    
        ::sort(v.begin(), v.end());
        auto it = ::unique(v.begin(), v.end());
        v.erase(it, v.end());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    结果为:
    在这里插入图片描述

    2.2 方式1:使用lambda

    	::sort(v.begin(), v.end());
    	// 使用lambda自定义比较规则:若x坐标相等,则两个Point相等
        auto it = ::unique(v.begin(), v.end(), [](Point a, Point b)
            {
                return a.X == b.X;
            });
        v.erase(it, v.end());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    运行结果为:
    在这里插入图片描述

    2.3 erase和resize

    在使用完unique之后,我们可以得到一个分界线iterator,有两种方式进行处理:

    //v.erase(it, v.end());删除从it往后的所有元素
    //v.resize((int)(::distance(v.begin(), it)));//保留从begin到it的所有元素
    
    • 1
    • 2

    3. 去重总结

    1. sort对集合中的元素进行排序:重载<或者lambda;
    2. unique对集合中的元素进行去重:重载==或者使用lambda;
    3. erase删除重复值或resize保留有效值。
  • 相关阅读:
    【AI理论学习】语言模型:掌握BERT和GPT模型
    嵌入式优势到底在哪里?
    Java学习路线图(完整详细2021版)
    vscode前端常用插件
    电脑快捷键
    一次偶然的钓鱼文件分析
    【Java技术专题】「Java8技术盲区」函数接口字典-看看还有哪些你所不知道函数接口
    [c++基础]-string类
    【React】面试题5题
    汇编的基础
  • 原文地址:https://blog.csdn.net/niaxiapia/article/details/126004812