定序谓词的链接(例如,对于std :: sort) [英] Chaining of ordering predicates (e.g. for std::sort)

查看:118
本文介绍了定序谓词的链接(例如,对于std :: sort)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

您可以将函数指针,函数对象(或boost lambda)传递给std :: sort,以定义要排序的容器的元素的严格弱排序。



但是,有时候(足够我打几次了),你想要能够链接原始的比较。



一个简单的例子将是如果您正在排序表示联系人数据的对象集合。有时您会想要按

姓,名,区号

进行排序。其他时间

姓氏

- 其他时间

年龄,名字,区号

p>

现在,你可以为每种情况编写一个附加的函数对象,但这违反了DRY原则 - 特别是如果每​​个比较都不太平凡。



看起来你应该能够写一个层次结构的比较函数 - 低层次的单一,原始,比较(例如名字<名字),然后更高层次称为低层次(可能用&&使用短路评估链接)来生成复合函数。



这种方法的麻烦是std: :sort接受一个二元谓词 - 谓词只能返回一个bool。所以,如果你正在撰写它们,你不能知道假是表示平等还是大于。你可以让你的低级谓词返回一个int,有三个状态 - 但是你必须将它们包装在更高级的谓词中,然后才能与std :: sort一起使用。



总之,这些不是不可逾越的问题。



因此,任何人都知道任何预先存在的库(如果它是一个std



[更新]



正如在一些评论中提到的 - 我已经开始编写自己的实现类来管理这个。这是相当最小的,可能有一些问题,一般。但是在这个基础上,对于任何感兴趣的人,这个类在这里:



http://pastebin.com/f52a85e4f



一些辅助函数(避免需要指定模板参数)在这里:



http://pastebin.com/fa03d66e

解决方案

你可以这样建立一个小链接系统:

 code> struct Type {
string first,last;
int age
};

struct CmpFirst {
bool operator()(const Type& lhs,const Type& rhs){return lhs.first< rhs.first; }
};

struct CmpLast {
bool operator()(const Type& lhs,const Type& rhs){return lhs.last< rhs.last; }
};

struct CmpAge {
bool operator()(const Type& lhs,const Type& rhs){return lhs.age< rhs.age; }
};

template< typename首先,typename第二>
struct Chain {
Chain(const First& f_,const Second& s_):f(f_),s(s_){}

bool operator ; lhs,const Type& rhs){
if(f(lhs,rhs))
return true;
if(f(rhs,lhs))
return false;

return s(lhs,rhs);
}

template< typename Next>
Chain< Chain,Next> chain(const Next& next)const {
return Chain< Chain,Next> (* this,next);
}

第一f;
秒;
};

struct False {bool operator()(const Type& lhs,const Type& rhs){return false; }};

template< typename Op>
Chain< False,Op> make_chain(const Op& op){return Chain< False,Op> (False(),op); }

然后使用它:

  vector< Type> v; // fill this baby up 

sort(v.begin(),v.end(),make_chain(CmpLast())。chain(CmpFirst())。chain(CmpAge()));

最后一行是有点冗长,但我认为它的目的是清楚的。


You can pass a function pointer, function object (or boost lambda) to std::sort to define a strict weak ordering of the elements of the container you want sorted.

However, sometimes (enough that I've hit this several times), you want to be able to chain "primitive" comparisons.

A trivial example would be if you were sorting a collection of objects that represent contact data. Sometimes you will want to sort by

last name, first name, area code

. Other times

first name, last name

- yet other times

age, first name, area code

... etc

Now, you can certainly write an additional function object for each case, but that violates the DRY principle - especially if each comparison is less trivial.

It seems like you should be able to write a hierarchy of comparison functions - the low level ones do the single, primitive, comparisons (e.g. first name < first name), then higher level ones call the lower level ones in succession (probably chaining with && to make use of short circuit evaluation) to generate the composite functions.

The trouble with this approach is that std::sort takes a binary predicate - the predicate can only return a bool. So if you're composing them you can't tell if a "false" indicates equality or greater than. You can make your lower level predicates return an int, with three states - but then you would have to wrap those in higher level predicates before they could be used with std::sort on their own.

In all, these are not insurmountable problems. It just seems harder than it should be - and certainly invites a helper library implementation.

Therefore, does anyone know of any pre-existing library (esp. if it's a std or boost library) that can help here - of have any other thoughts on the matter?

[Update]

As mentioned in some of the comments - I've gone ahead and written my own implementation of a class to manage this. It's fairly minimal, and probably has some issues with it in general. but on that basis, for anyone interested, the class is here:

http://pastebin.com/f52a85e4f

And some helper functions (to avoid the need to specify template args) is here:

http://pastebin.com/fa03d66e

解决方案

You could build a little chaining system like so:

struct Type {
  string first, last;
  int age;
};

struct CmpFirst {
  bool operator () (const Type& lhs, const Type& rhs) { return lhs.first < rhs.first; }
};

struct CmpLast {
  bool operator () (const Type& lhs, const Type& rhs) { return lhs.last < rhs.last; }
};

struct CmpAge {
  bool operator () (const Type& lhs, const Type& rhs) { return lhs.age < rhs.age; }
};

template <typename First, typename Second>
struct Chain {
  Chain(const First& f_, const Second& s_): f(f_), s(s_) {}

  bool operator () (const Type& lhs, const Type& rhs) {
    if(f(lhs, rhs))
      return true;
    if(f(rhs, lhs))
      return false;

    return s(lhs, rhs);
  }

  template <typename Next>
  Chain <Chain, Next> chain(const Next& next) const {
     return Chain <Chain, Next> (*this, next);
  }

  First f;
  Second s;
};

struct False { bool operator() (const Type& lhs, const Type& rhs) { return false; } };

template <typename Op>
Chain <False, Op> make_chain(const Op& op) { return Chain <False, Op> (False(), op); }

Then to use it:

vector <Type> v;  // fill this baby up

sort(v.begin(), v.end(), make_chain(CmpLast()).chain(CmpFirst()).chain(CmpAge()));

The last line is a little verbose, but I think it's clear what's intended.

这篇关于定序谓词的链接(例如,对于std :: sort)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆