4

特にC++での並べ替えでは、より大きな構造を比較するために一連のフィールドを比較している状況に頻繁に遭遇します。簡単な例:

struct Car{
    Manufacturer make;
    ModelName model;
    Year year;
};

bool carLessThanComparator( const Car & car1, const Car & car2 ){
    if( car1.make < car2.make ){
        return true;
    }else if( car1.make == car2.make ){
        if( car1.model < car2.model ){
            return true;
        }else if( car1.model == car2.model ){
            if( car1.year < car2.year ){
                return true;
            }
        }
    }

    return false;
}

私の本能的なアプローチは、特に3つ以上の分野では面倒に思えます。この一連の比較をC++でどのように構成しますか?他の言語は、より簡潔またはエレガントな構文を提供しますか?

4

7 に答える 7

5

さて、関数がif句でreturnにヒットした場合、明示的なelseは必要ありません。これは、すでにベイルアウトされているためです。これにより、「インデントバレー」を節約できます。

bool carLessThanComparator( const Car & car1, const Car & car2 ) {
    if( car1.make < car2.make )
        return true;

    if ( car1.make != car2.make )
        return false;

    if( car1.model < car2.model )
        return true;

    if( car1.model != car2.model )
        return false;

    if( car1.year < car2.year )
        return true;

    return false;
}

MarkusQのLISPish短絡アプローチも気に入っています。

于 2009-02-28T05:23:01.430 に答える
4

古い質問だと思いますが、将来の訪問者のために: 最新の C++11 ソリューションはstd::tieを使用することです

struct Car{
    Manufacturer make;
    ModelName model;
    Year year;
};

bool operator<(Car const& lhs, Car const& rhs)
{
    return std::tie(lhs.make, lhs.model, lhs.year) < std::tie(rhs.make, rhs.model, rhs.year);
}

std::tiestd::tuple上記の比較演算子が に委譲されるように、構造体を に変換しstd::tuple::operator<ます。これにより、メンバーが にマーシャリングされる順序に関して、辞書式の比較が行われstd::tieます。

辞書式の比較は、この質問に対する他の解決策と同じように短絡的です。しかし、C++ ラムダ式内でオンザフライで定義できるほど簡潔です。プライベート データ メンバーを持つクラスの場合、クラス内でfriend関数として定義するのが最適です。

于 2013-03-30T21:25:11.807 に答える
4

これが頻繁に発生する場合は、次のようなテンプレートを共通ヘッダーに入れることができます。

template<typename T, typename A1, typename A2, typename A3>
bool
do_less_than(
        const typename T& t1,
        const typename T& t2,
        const typename A1 typename T::* a1,
        const typename A2 typename T::* a2,
        const typename A3 typename T::* a3)
{
    if ((t1.*a1) < (t2.*a1)) return true;
    if ((t1.*a1) != (t2.*a1)) return false;
    if ((t1.*a2) < (t2.*a2)) return true;
    if ((t1.*a2) != (t2.*a2)) return false;
    return (t1.*a3) < (t2.*a3);
}

必要に応じて、引数の数が異なる他のテンプレートを追加します。より小さい関数ごとに、次のようなことができます。

bool carLessThanComparator(const Car& car1, const Car& car2)
{
    return do_less_than(car1, car2, &Car::make, &Car::model, &Car::year);
}
于 2009-02-28T05:43:43.377 に答える
2
bool carLessThanComparator( const Car & car1, const Car & car2 ){
    return (
      ( car1.make  < car2.make  ) or (( car1.make  == car2.make  ) and
      ( car1.model < car2.model ) or (( car1.model == car2.model ) and
      ( car1.year  < car2.year  ) 
      )));

--MarkusQ

于 2009-02-28T05:17:42.503 に答える
2

OPと同じことを考えていて、この質問に出くわしました。答えを読んだ後、私はjanmとRnRに触発されて、比較されたメンバーlexicographicalMemberCompareでのみ使用するテンプレート関数を作成しました。operator<また、boost :: tupleを使用して、必要な数のメンバーを指定できるようにします。ここにあります:

#include <iostream>
#include <string>
#include <boost/tuple/tuple.hpp>

template <class T, class Cons>
struct LessThan
{
    static bool compare(const T& lhs, const T& rhs, const Cons& cons)
    {
        typedef LessThan<T, typename Cons::tail_type> NextLessThan;
        typename Cons::head_type memberPtr = cons.get_head();
        return lhs.*memberPtr < rhs.*memberPtr ?
            true :
            (rhs.*memberPtr < lhs.*memberPtr  ?
                false :
                NextLessThan::compare(lhs, rhs, cons.get_tail()));
    }
};

template <class T>
struct LessThan<T, class boost::tuples::null_type>
{
    static bool compare(const T& lhs, const T& rhs,
                        const boost::tuples::null_type& cons)
    {
        return false;
    }
};

template <class T, class Tuple>
bool lexicographicalMemberCompare(const T& lhs, const T& rhs,
                                  const Tuple& tuple)
{
    return LessThan<T, typename Tuple::inherited>::compare(lhs, rhs, tuple);
}

struct Car
{
    std::string make;
    std::string model;
    int year;
};

bool carLessThanCompare(const Car& lhs, const Car& rhs)
{
    return lexicographicalMemberCompare(lhs, rhs,
        boost::tuples::make_tuple(&Car::make, &Car::model, &Car::year));
}

int main()
{
    Car car1 = {"Ford", "F150", 2009};
    Car car2 = {"Ford", "Escort", 2009};
    std::cout << carLessThanCompare(car1, car2) << std::endl;
    std::cout << carLessThanCompare(car2, car1) << std::endl;
    return 0;
}

これが誰かに役立つことを願っています。

于 2010-02-04T06:19:17.773 に答える