24

がありmap、マップで最小値(右側)を見つけたいと思います。これが私がそれをした方法です:

bool compare(std::pair<std::string ,int> i, pair<std::string, int> j) {
  return i.second < j.second;
}
////////////////////////////////////////////////////
std::map<std::string, int> mymap;

mymap["key1"] = 50;
mymap["key2"] = 20;
mymap["key3"] = 100;

std::pair<char, int> min = *min_element(mymap.begin(), mymap.end(), compare); 
std::cout << "min " << min.second<< " " << std::endl;

上記のコードは正常に機能し、最小値を取得できます。ただし、このコードを次のようにクラス内に配置すると、機能しないようです。

int MyClass::getMin(std::map<std::string, int> mymap) {
  std::pair<std::string, int> min = *min_element(mymap.begin(), mymap.end(), 
                                                 (*this).compare);
                                                 // Error probably due to "this".
  return min.second; 
}

bool MyClass::compare(
    std::pair<std::string, int> i, std::pair<std::string, int> j) { 
  return i.second < j.second; 
}

クラスでコードを機能させるにはどうすればよいですか?compareまた、追加の関数を書く必要のないより良い解決策はありますか?

4

5 に答える 5

19

C ++ 11では、これを行うことができます。

auto it = min_element(pairs.begin(), pairs.end(),
                      [](decltype(pairs)::value_type& l, decltype(pairs)::value_type& r) -> bool { return l.second < r.second; });

または、次のような優れた関数に入れます(私はテンプレートの第一人者ではないことに注意してください。これは、多くの点でおそらく間違っています)。

template<typename T>
typename T::iterator min_map_element(T& m)
{
    return min_element(m.begin(), m.end(), [](typename T::value_type& l, typename T::value_type& r) -> bool { return l.second < r.second; });
}

C ++ 14を使用すると、さらに単純化されて次のようになります。

min_element(pairs.begin(), pairs.end(),
            [](const auto& l, const auto& r) { return l.second < r.second; });
于 2014-11-10T11:41:37.513 に答える
18

いくつかのオプションがあります。これを行うための「最良の」方法は、ファンクターを使用することです。これは、呼び出すのが最も速いことが保証されています。

typedef std::pair<std::string, int> MyPairType;
struct CompareSecond
{
    bool operator()(const MyPairType& left, const MyPairType& right) const
    {
        return left.second < right.second;
    }
};



int MyClass::getMin(std::map<std::string, int> mymap) 
{
  std::pair<std::string, int> min 
      = *min_element(mymap.begin(), mymap.end(), CompareSecond());
  return min.second; 
}

CompareSecond(クラスを内部にネストすることもできますMyClass

ただし、現在使用しているコードを使用すると、コードを簡単に変更して機能させることができます。関数staticを作成し、正しい構文を使用するだけです。

static bool 
MyClass::compare(std::pair<std::string, int> i, std::pair<std::string, int> j) 
{ 
  return i.second < j.second; 
}

int MyClass::getMin(std::map<std::string, int> mymap) 
{
  std::pair<std::string, int> min = *min_element(mymap.begin(), mymap.end(), 
                                                 &MyClass::compare);
  return min.second; 
}
于 2010-04-17T17:18:35.613 に答える
2

問題はこれです:

bool MyClass::compare

呼び出されるクラスのインスタンスが必要です。つまり、単に呼び出すことはできませんがMyClass::compare、が必要someInstance.compareです。ただし、min_element前者が必要です。

簡単な解決策はそれを作ることstaticです:

static bool MyClass::compare

// ...

min_element(mymap.begin(), mymap.end(), &MyClass::compare);

これにより、インスタンスを呼び出す必要がなくなり、コードは正常になります。ただし、ファンクターを使用してより一般的にすることができます。

struct compare2nd
{
    template <typename T>
    bool operator()(const T& pLhs, const T& pRhs)
    {
        return pLhs.second < pRhs.second;
    }
};

min_element(mymap.begin(), mymap.end(), compare2nd());

これは、各ペアから2番目を取得して取得するだけで、任意のペアで機能します。それは一般的なものにすることができますが、それは少し多すぎます。

十分な値で検索する必要がある場合は、BoostのBimapを使用することをお勧めします。これは双方向のマップであるため、キーと値の両方を使用して検索できます。バリューキーマップの前面を取得するだけです。

最後に、マップに入る最小要素をいつでも追跡できます。新しい値を挿入するたびに、それが現在の値よりも低いかどうかを確認し(おそらく、マップペアへのポインタであるはずであり、nullとして開始します)、低い場合は、新しい最小値を指します。最低値の要求は、ポインターの間接参照と同じくらい簡単になります。

于 2010-04-17T17:30:36.987 に答える
2

私は実際に別の質問があります:あなたが定期的に右側の値の最小値を取得する必要がある場合、あなたはamapが最良の構造であるよりも確かですか?

同じオブジェクトのセットにインデックスを付ける複数の方法のこれらの問題には、一般的に使用することをお勧めしBoost.MultiIndexます...ただし、この「逆マッピング」ビットのみが必要な場合は、Boost.Bimapより簡単になる可能性があります。

このようにして、最小値を探すときに線形探索を行うことはありません:)

于 2010-04-18T10:25:05.360 に答える
2

C ++ 14

Timmmmの回答に関するJonathanGeislerのコメントで述べたように、C ++ 14では、ラムダ関数パラメーターを型指定子で宣言できます。その結果、次のようにTimmmmのラムダベースの行を短くする(そして読みやすさを向上させる)ことができます。automin_element

auto it = std::min_element(std::begin(mymap), std::end(mymap),
                           [](const auto& l, const auto& r) { return l.second < r.second; });

注1:この行をMyClass::getMin()関数に入れる場合は、を返す必要がありますit->second。ただし、空のマップを説明するには、return次のように(または同様の方法で)行を調整する必要があります。

return it == mymap.end() ? -1 : it->second;

注2:Lance Diduckconstでも言及されているように、関数を参照してマップを渡す必要がありますgetMin()。あなたがそれをした方法で、あなたは地図全体の不必要なコピーを作成しています。

Ideoneのコード

于 2019-06-06T14:03:57.297 に答える