How can I find the minimum value in a map?

前端 未结 5 1734
夕颜
夕颜 2020-12-05 23:49

I have a map and I want to find the minimum value (right-hand side) in the map. Here is how I did it:

bool compare(std::pair

        
相关标签:
5条回答
  • 2020-12-06 00:16

    You have a few options. The "best" way to do this is with a functor, this is guaranteed to be the fastest to call:

    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; 
    }
    

    (You can also nest the CompareSecond class inside MyClass.

    With the code you have now, you can easily modify it to work, however. Just make the function static and use the correct syntax:

    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; 
    }
    
    0 讨论(0)
  • 2020-12-06 00:28

    I actually have another question: if you need to regularly obtain the minimum of the right-hand side values are you sure than a map is the best structure ?

    I would suggest using Boost.MultiIndex in general for these problems of multiple ways of indexing the same set of objects... but if you only need this "reverse-mapping" bit Boost.Bimap might prove easier.

    This way you won't have a linear search when looking for the minimum :)

    0 讨论(0)
  • 2020-12-06 00:37

    C++14

    As mentioned in Jonathan Geisler's comment on Timmmm's answer, C++14 allows lambda function parameters to be declared with the auto type specifier. As a result, you can shorten Timmmm's lambda-based min_element line (and improve its readability) as follows:

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

    Note 1: If you put this line into your MyClass::getMin() function, you have to return it->second. However, to account for an empty map, you should adapt the return line as follows (or similar):

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

    Note 2: As also mentioned by Lance Diduck, you should be passing the map by const reference to your getMin() function. The way you did it, you are creating an unnecessary copy of the whole map.

    Code on Ideone

    0 讨论(0)
  • 2020-12-06 00:41

    The problem is that this:

    bool MyClass::compare
    

    Requires an instance of the class to be called on. That is, you can't just call MyClass::compare, but you need someInstance.compare. However, min_element needs the former.

    The easy solution is to make it static:

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

    This no longer requires an instance to be called on, and your code will be fine. You can make it more general with a functor, though:

    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());
    

    All this does is grab the second from each pair and grab them, works with any pair. It could be made for general, but that's a bit too much.

    If you need to look up by value enough, I recommend you use Boost's Bimap. It's a bi-directional map, so both the key and value can be used to lookup. You would simply get the front of the value-key map.

    Lastly, you can always just keep track of the minimum element going into your map. Every time you insert a new value, check if it's lower than your current value (and that should be probably be a pointer to a map pair, start it as null), and if it's lower, point to the new lowest. Requesting the lowest becomes as simple as dereferencing a pointer.

    0 讨论(0)
  • 2020-12-06 00:42

    In C++11 you can do this:

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

    Or put it in a nice function like this (note I'm not a template guru; this is probably wrong in many ways):

    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; });
    }
    

    With C++14, it further simplifies to:

    min_element(pairs.begin(), pairs.end(),
                [](const auto& l, const auto& r) { return l.second < r.second; });
    
    0 讨论(0)
提交回复
热议问题