C++ 按固定组件对元组容器进行排序

C++ 按固定组件对元组容器进行排序,c++,sorting,templates,c++11,C++,Sorting,Templates,C++11,给定一个成对或元组的容器,我们希望通过指定一个二进制谓词和一个固定组件对其进行排序,以便排序只关注每个元组的该组件。此工作代码说明了这一点: #include <iostream> #include <tuple> #include <vector> #include <string> #include <algorithm> #include <functional> template <int N, typena

给定一个成对或元组的容器,我们希望通过指定一个二进制谓词和一个固定组件对其进行排序,以便排序只关注每个元组的该组件。此工作代码说明了这一点:

#include <iostream>
#include <tuple>
#include <vector>
#include <string>
#include <algorithm>
#include <functional>

template <int N, typename BinaryPredicate, typename ForwardIterator>
void sortByFixedComponent (ForwardIterator first, ForwardIterator last) {
    std::sort (first, last, [](const typename ForwardIterator::value_type& x, const typename ForwardIterator::value_type& y)->bool {
        return BinaryPredicate()(std::get<N>(x), std::get<N>(y));
    });
}

// ------------------- Testing --------------------
struct Length {
    bool operator()(const std::string& a, const std::string& b) const {return a.length() < b.length();}
};

int main() {
    std::vector<std::pair<int,int>> v = {
        {3,5}, {6,8}, {3,7}, {1,9}, {3,1}, {1,2}, {3,5}
    };
    sortByFixedComponent<0, std::less<int>> (v.begin(), v.end());  // Sorts v according to the first components.
    for (const std::pair<int,int>& x : v) std::cout << "(" << x.first << ", " << x.second << ") ";  std::cout << '\n';
    sortByFixedComponent<1, std::greater<int>> (v.begin(), v.end());  // Sorts v according to the second components (in reverse order).
    for (const std::pair<int,int>& x : v) std::cout << "(" << x.first << ", " << x.second << ") ";  std::cout << '\n';

    using Tuple = std::tuple<int, std::string, char>;
    std::vector<Tuple> t = {
        Tuple{3,"hi",'q'}, Tuple{6,"dog",'u'}, Tuple{3,"hello",'c'}, Tuple{1,"cat",'r'}, Tuple{3,"no",'a'}, Tuple{1,"orange",'z'}, Tuple{3,"door",'x'}
    };
    sortByFixedComponent<1, Length> (t.begin(), t.end());  // Sorts t according to the second components in order of string lengths.
}
最后,在main()中,我希望

sortByFixedComponent<Z<2,0,1>, P<std::greater<char>, Length, std::less<int>>> (t.begin(), t.end());
sortByFixedComponent(t.begin(),t.end());
工作。它是用来分拣集装箱的

    std::vector<Tuple> t = {
        Tuple{3,"hi",'q'}, Tuple{6,"dog",'u'}, Tuple{3,"hello",'c'}, Tuple{1,"cat",'r'}, Tuple{3,"no",'a'}, Tuple{1,"orange",'z'}, Tuple{3,"door",'x'}
    };
std::vector t={
元组{3,“hi”,“q”},元组{6,“dog”,“u”},元组{3,“hello”,“c”},元组{1,“cat”,“r”},元组{3,“no”,“a”},元组{1,“orange”,“z”},元组{3,“door”,“x”}
};
因此,首先查看char组件(对元组进行排序,使其按字母顺序排列),然后在关系中查看int组件(对关系进行排序,使其按相反顺序排列),然后如果仍然存在任何关系,则查看string组件(对关系进行排序,使字符串从最短到最长)。 任何帮助都将不胜感激。当我解决第一个例子时,这个问题就出现了,但随后我想知道它们之间的联系

看一个具体的例子。在我的第一个示例中,输出是(1,9)(1,2)(3,5)(3,7)(3,1)(3,5)(6,8),因为第一个分量是从最小到最大排序的。但是4对以3开头。让我们用另一个比较器根据第二个分量对这4个进行排序。目标是对这一点的概括

更新: 我认为解决这个问题的关键不是递归,所以基本上我上面的尝试可以放弃。我认为需要的是二进制谓词的组合。因此,我的新出发点是使用这个helper结构:

template <typename, typename...> struct PredicateBuilder;

template <typename T, typename BinaryPredicate> 
struct PredicateBuilder<T, BinaryPredicate> {
    const BinaryPredicate binaryPredicate;
    PredicateBuilder (BinaryPredicate func): binaryPredicate (func) {}
    bool operator() (const T& a, const T& b) const {return binaryPredicate (a,b);}
};

template <typename T, typename First, typename... Rest>
struct PredicateBuilder<T, First, Rest...> : PredicateBuilder<T, Rest...> {
    const First binaryPredicate;
    PredicateBuilder (First first, Rest... rest): PredicateBuilder<T, Rest...> (rest...), binaryPredicate (first) {}
    bool operator () (const T& a, const T& b) const {
        if (binaryPredicate (a,b))
            return true;
        else if (binaryPredicate (b,a)) 
            return false;
        else
            return PredicateBuilder<T, Rest...>::operator()(a,b);
    }
};
模板结构PredicateBuilder;
模板
结构谓词生成器{
常量二进制谓词二进制谓词;
PredicateBuilder(BinaryPredicate func):BinaryPredicate(func){}
bool运算符()(常量T&a,常量T&b)常量{返回二进制谓词(a,b);}
};
模板
结构PredicateBuilder:PredicateBuilder{
const第一个二进制谓词;
PredicateBuilder(第一个,Rest…Rest):PredicateBuilder(Rest…),binaryPredicate(第一个){}
布尔运算符()(常数T&a、常数T&b)常数{
if(二元谓词(a,b))
返回true;
else if(二进制谓词(b,a))
返回false;
其他的
返回谓词builder::operator()(a,b);
}
};
将通过元素3、元素2和元素1对
foo
进行排序

接下来要做的是将每个子元素投影到其自己的排序域中。仍然不是你想要的,而是更接近

为了解决这一问题,我将致力于管道设计,并根据制定变量
订单

管道使您可以获得,然后投影到新空间

template<class... Fs>
struct order_by_t;

template<>
struct order_by_t<> {
  template<class Lhs, class Rhs>
  bool operator(Lhs&&lhs, Rhs&&rhs)const {
    return false;
  }
};
template<class F>
struct order_by_t<F> {
  F f;
  template<class Lhs, class Rhs>
  bool operator(Lhs&&lhs, Rhs&&rhs)const {
    return f(std::forward<Lhs>(lhs)) < f(std::forward<Rhs>(rhs));
  }
};
template<class F, class...Fs>
struct order_by_t<F, Fs...>:
  order_by<Fs...>
{
  template<class T, class...Ts>
  order_by_t(T&&t, Ts&&...ts):
    order_by_t<Fs...>{std::forward<Ts>(ts)...},
    f(std::forward<T>(t))
  {}
  F f;
  template<class Lhs, class Rhs>
  bool operator(Lhs&&lhs, Rhs&&rhs)const {
    auto&& lhs_ = f(lhs);
    auto&& rhs_ = f(rhs);
    if (lhs_<rhs_) return true;
    if (rhs_<lhs_) return false;
    return order_by_t<Fs...>::operator()
      (std::forward<Lhs>(lhs),std::forward<Rhs>(rhs));
  }
};
template<class... Fs>
order_by_t< std::decay_t<Fs>... > order_by( Fs&&... fs ) {
  return {std::forward<Fs>(fs)...};
}
我们就快到了!将
长度
替换为:

struct get_length {
  size_t operator()( std::string const& s ) const {
    return s.size();
  }
};
struct reversed_sort_t {
  template<class T>
  struct helper {
    T&& t;
    template<class A, class B>
    friend bool operator<(helper<A>&& lhs, helper<B>&& rhs) {
      return std::forward<B>(rhs.t) < std::forward<A>(lhs.t);
    }
  };
  template<class T>
  helper<T> operator()(T&& t) const {
    return {std::forward<T>(t)};
  }
};

//  sortByFixedComponent<Z<2,0,1>, P<std::greater<char>, Length, std::less<int>>> (t.begin(), t.end());  // Want this line to work.
auto ordering = order_by(
  compose( reversed_sort_t{}, get_t<2>{} ),
  compose( get_length{}, get_t<0>{} ),
  get_t<1>{}
);
std::sort( t.begin(), t.end(), ordering );
struct get\u长度{
size_t运算符()(std::string const&s)const{
返回s.size();
}
};
结构反向排序{
模板
结构辅助程序{
T&T;
模板
friend bool operator::type
如果您缺少该别名,或者使用blah_t=typename std::blah::type;
编写您自己的
\t
别名,如
模板。还有一些代码通过
的C++14
std::result\u得到了很大的改进,如果当前为0

最奇怪的顺序映射是
reversed\u sort\u t
,它映射了
t->reversed\u sort\u t::helper
,其中
helper
是一种类型,它只支持引用语义默认副本,并反转
的应用程序,我想我明白了

#include <iostream>
#include <tuple>
#include <vector>
#include <string>
#include <algorithm>
#include <functional>

template <typename, typename, typename> struct TuplePredicateBuilder;

template <template <int...> class Z, int N, template <typename...> class P, typename BinaryPredicate, typename Iterator>
struct TuplePredicateBuilder<Z<N>, P<BinaryPredicate>, Iterator> {
    bool operator()(const typename Iterator::value_type& x, const typename Iterator::value_type& y) {
        return BinaryPredicate()(std::get<N>(x), std::get<N>(y));
    }
};

template <template <int...> class Z, int FirstInt, int... RestInt, template <typename...> class P, typename FirstBinaryPredicate, typename... RestBinaryPredicate, typename Iterator>
struct TuplePredicateBuilder<Z<FirstInt, RestInt...>, P<FirstBinaryPredicate, RestBinaryPredicate...>, Iterator> : TuplePredicateBuilder<Z<RestInt...>, P<RestBinaryPredicate...>, Iterator> {
    bool operator()(const typename Iterator::value_type& x, const typename Iterator::value_type& y) {
        if (FirstBinaryPredicate()(std::get<FirstInt>(x), std::get<FirstInt>(y)))
            return true;
        else if (FirstBinaryPredicate()(std::get<FirstInt>(y), std::get<FirstInt>(x)))
            return false;
        else
            return TuplePredicateBuilder<Z<RestInt...>, P<RestBinaryPredicate...>, Iterator>::operator()(x,y);
    }
};

template <typename, typename, typename> struct SortByFixedComponent;

template <template <int...> class Z, int N, template <typename...> class P, typename BinaryPredicate, typename Iterator>
struct SortByFixedComponent<Z<N>, P<BinaryPredicate>, Iterator> {
    void operator()(Iterator first, Iterator last) {
        std::sort (first, last, [](const typename Iterator::value_type& x, const typename Iterator::value_type& y)->bool {
            return BinaryPredicate()(std::get<N>(x), std::get<N>(y));
        });
    }
};

template <template <int...> class Z, int... Is, template <typename...> class P, typename... BinaryPredicates, typename Iterator>
struct SortByFixedComponent<Z<Is...>, P<BinaryPredicates...>, Iterator> {
    void operator()(Iterator first, Iterator last) {
        std::sort (first, last, [](const typename Iterator::value_type& x, const typename Iterator::value_type& y)->bool {
            return TuplePredicateBuilder<Z<Is...>, P<BinaryPredicates...>, Iterator>()(x,y);
        });
    }
};

template <typename Components, typename BinaryPredicates, typename Iterator>
void sortByFixedComponent (Iterator first, Iterator last) {
    SortByFixedComponent<Components, BinaryPredicates, Iterator>()(first, last);
}
首先,第三个成分按字母倒序排列。然后,在这4个以u结尾的元组中,字符串成分按从短到长的顺序排列。还有三个关系,所以在这些关系中,int成分按从最小到最大的顺序排列。我希望之前的阅读者现在理解我的问题

我现在将研究雅克的解决方案,看看他的方法是否真的不同

更新:我只想补充一点,我找到了一种更通用的方法来编写上述内容(经过测试,得到了完全相同的输出),使用:

//通用谓词生成器,以便TuplePredicateBuilder以外的其他类型也可以从中继承。
模板结构谓词生成器;
模板
结构谓词生成器{
布尔运算符()(常量T&a,常量T&b)常量{返回二进制谓词()(a,b);}
};
模板
结构PredicateBuilder:PredicateBuilder{
布尔运算符()(常数T&a,常数T&b)常数{
if(First()(a,b))
返回true;
else if(First()(b,a))
返回false;
其他的
返回谓词builder::operator()(a,b);
}
};
模板
结构二进制谓词组件{
bool运算符()(常量typename迭代器::value\u type&x,常量typename迭代器::value\u type&y){
返回BinaryPredicate()(std::get(x),std::get(y));
}
};
模板结构TuplePredicateBuilder;
模板
结构TuplePredicateBuilder:
谓词生成器{};

tl;aka博士找不到问题我在上一部分澄清了我的问题。首先查看字符组件(按字母顺序排列元组),然后在这些关系中查看int组件(按相反顺序排列关系),如果仍然存在任何关系,则查看字符串组件(对连接进行排序,使字符串从最短到最长)。如果main()中的这个测试通过,那么整个算法应该是正确的。我对你的问题很感兴趣,但你的代码超出了我的理解。简单的英文描述你正在尝试做什么(而不是你目前为止做了什么)会有帮助的。好的,我们有一个元组容器。让我们对它们进行排序。如何排序?让我们关注每个元组的第三个组件(假设为int),然后对元组进行排序,使第三个组件按相反的顺序排列。但是有一些联系(一些元组具有相同的第三个组件)
std::sort( foo.begin(), foo.end(), order_by( retie<3,2,1>{} ) );
template<class... Fs>
struct order_by_t;

template<>
struct order_by_t<> {
  template<class Lhs, class Rhs>
  bool operator(Lhs&&lhs, Rhs&&rhs)const {
    return false;
  }
};
template<class F>
struct order_by_t<F> {
  F f;
  template<class Lhs, class Rhs>
  bool operator(Lhs&&lhs, Rhs&&rhs)const {
    return f(std::forward<Lhs>(lhs)) < f(std::forward<Rhs>(rhs));
  }
};
template<class F, class...Fs>
struct order_by_t<F, Fs...>:
  order_by<Fs...>
{
  template<class T, class...Ts>
  order_by_t(T&&t, Ts&&...ts):
    order_by_t<Fs...>{std::forward<Ts>(ts)...},
    f(std::forward<T>(t))
  {}
  F f;
  template<class Lhs, class Rhs>
  bool operator(Lhs&&lhs, Rhs&&rhs)const {
    auto&& lhs_ = f(lhs);
    auto&& rhs_ = f(rhs);
    if (lhs_<rhs_) return true;
    if (rhs_<lhs_) return false;
    return order_by_t<Fs...>::operator()
      (std::forward<Lhs>(lhs),std::forward<Rhs>(rhs));
  }
};
template<class... Fs>
order_by_t< std::decay_t<Fs>... > order_by( Fs&&... fs ) {
  return {std::forward<Fs>(fs)...};
}
template<size_t I>
struct get_t {
  template<class Tup>
  auto operator()(Tup&&tup)const->
  decltype(std::get<I>(tup))
  { return std::get<I>(tup); }
};
template<class A, class B>
struct compose_t {
  A a; B b;
  template<class... Ts>
  auto operator()(Ts&&...ts)const->
  std::result_of_t< A const&( std::result_of_T< B const&(Ts...) > ) >
  {
    return a(b(std::forward<Ts>(ts)...));
  }
  // if you have a SFINAE enabled result_of, this is also useful.
  // if you don't, don't include this overload (it isn't used in this code):
  #if 0
  template<class... Ts>
  auto operator()(Ts&&...ts)const->
  std::result_of_t< A const&( std::result_of_T< B const&(Ts) >... ) >
  {
    return a(b(std::forward<Ts>(ts))...);
  }
  #endif
};
template<class A, class B>
compose_t< std::decay_t<A>, std::decay_t<B> >
compose(A&& a, B&& b) {
  return {std::forward<A>(a), std::forward<B>(b)};
}
struct get_length {
  size_t operator()( std::string const& s ) const {
    return s.size();
  }
};
struct reversed_sort_t {
  template<class T>
  struct helper {
    T&& t;
    template<class A, class B>
    friend bool operator<(helper<A>&& lhs, helper<B>&& rhs) {
      return std::forward<B>(rhs.t) < std::forward<A>(lhs.t);
    }
  };
  template<class T>
  helper<T> operator()(T&& t) const {
    return {std::forward<T>(t)};
  }
};

//  sortByFixedComponent<Z<2,0,1>, P<std::greater<char>, Length, std::less<int>>> (t.begin(), t.end());  // Want this line to work.
auto ordering = order_by(
  compose( reversed_sort_t{}, get_t<2>{} ),
  compose( get_length{}, get_t<0>{} ),
  get_t<1>{}
);
std::sort( t.begin(), t.end(), ordering );
#include <iostream>
#include <tuple>
#include <vector>
#include <string>
#include <algorithm>
#include <functional>

template <typename, typename, typename> struct TuplePredicateBuilder;

template <template <int...> class Z, int N, template <typename...> class P, typename BinaryPredicate, typename Iterator>
struct TuplePredicateBuilder<Z<N>, P<BinaryPredicate>, Iterator> {
    bool operator()(const typename Iterator::value_type& x, const typename Iterator::value_type& y) {
        return BinaryPredicate()(std::get<N>(x), std::get<N>(y));
    }
};

template <template <int...> class Z, int FirstInt, int... RestInt, template <typename...> class P, typename FirstBinaryPredicate, typename... RestBinaryPredicate, typename Iterator>
struct TuplePredicateBuilder<Z<FirstInt, RestInt...>, P<FirstBinaryPredicate, RestBinaryPredicate...>, Iterator> : TuplePredicateBuilder<Z<RestInt...>, P<RestBinaryPredicate...>, Iterator> {
    bool operator()(const typename Iterator::value_type& x, const typename Iterator::value_type& y) {
        if (FirstBinaryPredicate()(std::get<FirstInt>(x), std::get<FirstInt>(y)))
            return true;
        else if (FirstBinaryPredicate()(std::get<FirstInt>(y), std::get<FirstInt>(x)))
            return false;
        else
            return TuplePredicateBuilder<Z<RestInt...>, P<RestBinaryPredicate...>, Iterator>::operator()(x,y);
    }
};

template <typename, typename, typename> struct SortByFixedComponent;

template <template <int...> class Z, int N, template <typename...> class P, typename BinaryPredicate, typename Iterator>
struct SortByFixedComponent<Z<N>, P<BinaryPredicate>, Iterator> {
    void operator()(Iterator first, Iterator last) {
        std::sort (first, last, [](const typename Iterator::value_type& x, const typename Iterator::value_type& y)->bool {
            return BinaryPredicate()(std::get<N>(x), std::get<N>(y));
        });
    }
};

template <template <int...> class Z, int... Is, template <typename...> class P, typename... BinaryPredicates, typename Iterator>
struct SortByFixedComponent<Z<Is...>, P<BinaryPredicates...>, Iterator> {
    void operator()(Iterator first, Iterator last) {
        std::sort (first, last, [](const typename Iterator::value_type& x, const typename Iterator::value_type& y)->bool {
            return TuplePredicateBuilder<Z<Is...>, P<BinaryPredicates...>, Iterator>()(x,y);
        });
    }
};

template <typename Components, typename BinaryPredicates, typename Iterator>
void sortByFixedComponent (Iterator first, Iterator last) {
    SortByFixedComponent<Components, BinaryPredicates, Iterator>()(first, last);
}
struct Length {
    bool operator()(const std::string& a, const std::string& b) const {return a.length() < b.length();}
};

template <typename...> struct P {};
template <int...> struct Z {};

template <typename Tuple, std::size_t N>
struct TuplePrinter {
    static void print(const Tuple& t) {
        TuplePrinter<Tuple, N-1>::print(t);
        std::cout << ", " << std::get<N-1>(t);
    }
};

template <typename Tuple>
struct TuplePrinter<Tuple, 1>{
    static void print (const Tuple& t) {std::cout << std::get<0>(t);}
};

template <typename... Args>
void print (const std::tuple<Args...>& t) {
    std::cout << "(";
    TuplePrinter<decltype(t), sizeof...(Args)>::print(t);
    std::cout << ")\n";
}

int main() {
    using Tuple = std::tuple<std::string, int, char>;
    std::vector<Tuple> t = {
        Tuple{"hi",3,'q'}, Tuple{"dog",6,'u'}, Tuple{"hello",3,'c'}, Tuple{"cat",1,'u'}, Tuple{"no",3,'a'}, Tuple{"orange",1,'u'}, Tuple{"red",3,'u'}
    };
    sortByFixedComponent<Z<2,0,1>, P<std::greater<char>, Length, std::less<int>>> (t.begin(), t.end());
    for (const Tuple& x : t)
        print(x);
}
(cat, 1, u)
(red, 3, u)
(dog, 6, u)
(orange, 1, u)
(hi, 3, q)
(hello, 3, c)
(no, 3, a)
// General predicate builder so that other types than TuplePredicateBuilder can inherit from this as well.
template <typename, typename...> struct PredicateBuilder;

template <typename T, typename BinaryPredicate> 
struct PredicateBuilder<T, BinaryPredicate> {
    bool operator()(const T& a, const T& b) const {return BinaryPredicate()(a,b);}
};

template <typename T, typename First, typename... Rest>
struct PredicateBuilder<T, First, Rest...> : PredicateBuilder<T, Rest...> {
    bool operator()(const T& a, const T& b) const {
        if (First()(a,b))
            return true;
        else if (First()(b,a)) 
            return false;
        else
            return PredicateBuilder<T, Rest...>::operator()(a,b);
    }
};

template <int N, typename BinaryPredicate, typename Iterator>
struct BinaryPredicateNthComponent {
    bool operator()(const typename Iterator::value_type& x, const typename Iterator::value_type& y) {
        return BinaryPredicate()(std::get<N>(x), std::get<N>(y));
    }
};

template <typename, typename, typename> struct TuplePredicateBuilder;

template <template <int...> class Z, int... Is, template <typename...> class P, typename... BinaryPredicates, typename Iterator>
struct TuplePredicateBuilder<Z<Is...>, P<BinaryPredicates...>, Iterator> : 
    PredicateBuilder<typename Iterator::value_type, BinaryPredicateNthComponent<Is, BinaryPredicates, Iterator>...> {};