使用STL对两个元素进行排序
Sorting just two elements using STL
我经常有两个变量 foo1
和 foo2
,它们是数字类型。它们代表某物的界限。
用户为他们提供价值,但就像一个顽固的音乐家,不一定是正确的顺序!
所以我的代码中充斥着像
这样的代码
if (foo2 < foo1){
std::swap(foo2, foo1);
}
当然,这是一种惯用排序,其中两个元素在内存中不一定连续。这让我想知道:是否有用于此的 STL 单行代码?
不,但是当您注意到您将相同的代码写了两次时,是时候为它编写一个函数了:
template<typename T, typename P = std::less<T>>
void swap_if(T& a, T& b, P p = P()) {
if (p(a, b)) {
using std::swap;
swap(a, b);
}
}
如果您要比较的值的数据类型尚未在 C++ 中。您需要重载比较运算符。
例如,如果你想比较 foo1 和 foo2
template <class T>
class Foo {
private:
int value; // value
public:
int GetValue() const {
return value;
}
};
bool operator<(const Foo& lhs, const Foo& rhs) {
return (lhs.GetValue() < rhs.GetValue());
}
如果您的值是某种类型的 int 或 double。然后就可以使用std::list<>::sort成员函数了。
例如:
std::list<int> integer_list;
int_list.push_back(1);
int_list.push_back(8);
int_list.push_back(9);
int_list.push_back(7);
int_list.sort();
for(std::list<int>::iterator list_iter = int_list.begin(); list_iter != int_list.end(); list_iter++)
{
std::cout<<*list_iter<<endl;
}
我建议退后一步,让类型系统为您完成工作:引入像 Bounds
(或 Interval
)这样的类型来解决这个问题。像
template <typename T>
class Interval {
public:
Interval( T start, T end ) : m_start( start ), m_end( end ) {
if ( m_start > m_end ) {
std::swap( m_start, m_end );
}
}
const T &start() const { return m_start; }
const T &end() const { return m_end; }
private:
T m_start, m_end;
};
这不仅集中了交换排序代码,还有助于尽早确定正确的顺序,这样您就不会一直传递两个元素,这意味着您甚至不需要一开始经常检查订单。
另一种避免该问题的方法是将边界表示为一对 'start value' 和 'length',其中 'length' 是无符号值。
std::minmax
returns 一对最小和最大的元素。您可以将其与 std::tie
.
一起使用
#include <algorithm>
#include <tuple>
#include <iostream>
int main()
{
int a = 7;
int b = 5;
std::tie(a, b) = std::minmax({a,b});
std::cout << a << " " << b; // output: 5 7
}
请注意,这与 if(a < b) std::swap(a,b);
版本不同。例如,这不适用于仅移动元素。
我经常有两个变量 foo1
和 foo2
,它们是数字类型。它们代表某物的界限。
用户为他们提供价值,但就像一个顽固的音乐家,不一定是正确的顺序!
所以我的代码中充斥着像
这样的代码if (foo2 < foo1){
std::swap(foo2, foo1);
}
当然,这是一种惯用排序,其中两个元素在内存中不一定连续。这让我想知道:是否有用于此的 STL 单行代码?
不,但是当您注意到您将相同的代码写了两次时,是时候为它编写一个函数了:
template<typename T, typename P = std::less<T>>
void swap_if(T& a, T& b, P p = P()) {
if (p(a, b)) {
using std::swap;
swap(a, b);
}
}
如果您要比较的值的数据类型尚未在 C++ 中。您需要重载比较运算符。
例如,如果你想比较 foo1 和 foo2
template <class T>
class Foo {
private:
int value; // value
public:
int GetValue() const {
return value;
}
};
bool operator<(const Foo& lhs, const Foo& rhs) {
return (lhs.GetValue() < rhs.GetValue());
}
如果您的值是某种类型的 int 或 double。然后就可以使用std::list<>::sort成员函数了。
例如:
std::list<int> integer_list;
int_list.push_back(1);
int_list.push_back(8);
int_list.push_back(9);
int_list.push_back(7);
int_list.sort();
for(std::list<int>::iterator list_iter = int_list.begin(); list_iter != int_list.end(); list_iter++)
{
std::cout<<*list_iter<<endl;
}
我建议退后一步,让类型系统为您完成工作:引入像 Bounds
(或 Interval
)这样的类型来解决这个问题。像
template <typename T>
class Interval {
public:
Interval( T start, T end ) : m_start( start ), m_end( end ) {
if ( m_start > m_end ) {
std::swap( m_start, m_end );
}
}
const T &start() const { return m_start; }
const T &end() const { return m_end; }
private:
T m_start, m_end;
};
这不仅集中了交换排序代码,还有助于尽早确定正确的顺序,这样您就不会一直传递两个元素,这意味着您甚至不需要一开始经常检查订单。
另一种避免该问题的方法是将边界表示为一对 'start value' 和 'length',其中 'length' 是无符号值。
std::minmax
returns 一对最小和最大的元素。您可以将其与 std::tie
.
#include <algorithm>
#include <tuple>
#include <iostream>
int main()
{
int a = 7;
int b = 5;
std::tie(a, b) = std::minmax({a,b});
std::cout << a << " " << b; // output: 5 7
}
请注意,这与 if(a < b) std::swap(a,b);
版本不同。例如,这不适用于仅移动元素。