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){}
};

main.cpp

#include <iostream>
#include <vector>
#include "Point.h"
#include <algorithm>

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. 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;
    }
};
// 调用已实现的<的操作符重载
::sort(v.begin(), v.end());

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

1.2 方式2:使用lambda

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

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

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());

运行结果为:
![在这里插入图片描述](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());

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

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

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;
    }
};

调用:

    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());

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

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());

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

2.3 erase和resize

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

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

3. 去重总结

  1. sort对集合中的元素进行排序:重载<或者lambda;
  2. unique对集合中的元素进行去重:重载==或者使用lambda;
  3. erase删除重复值或resize保留有效值。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值