Link to home
Start Free TrialLog in
Avatar of healingtao
healingtao

asked on

map sort question

I map with the key that consists of 2 strings. I need to sort this map sometimes by the either 1st string or sometimes by second string. How do I do this?
Does it make sense to create a key class that has 2 string variables and do it with this class?
Here is an example of what I need, the second string part of my key is rating and my sort specifically needs to be
1) AAA
2) AA
3) A
4) BBB
5) BB
6) B

Is there a way to override map to allow me to sort specifically for the case above?
I need to somehow be able to override sort that map uses. Or is there a better way?

Thanks in advance
Avatar of jkr
jkr
Flag of Germany image

It IMHO would be easier and more effective to use two maps that have their own sort order and store refereces to the objects that you want them to hold.
Avatar of efn
efn

>  I need to sort this map sometimes by the either 1st string or sometimes by second string.

This is a bit ambiguous.  If you mean that you want to read entries from the map in key sequence and you want to be able to read it in two different sequences defined by two different keys, then I agree with jkr that you should use two maps as indexes to objects.

However, if you mean you want one sequence where the ordering takes two strings into account, then you are on the right track.  You should create a key class that contains two strings and define an operator < for that class.  You can make that operator do whatever you want, and the map will automatically use it to order objects by these keys.
STL sort recieve functor(or function) as parameters, by which you can you can decide the sort algorithm.
bool sort_1st_string(const Key& k1, const Key& k2)
{
    return k1.str1 < k2.str2;
}

bool sort_2nd_string(const Key& k1, const Key& k2)
{
   return k1.str2 < k2.str2;
}

sort(map.begin(), map.end(), sort_1st_string);

sort(map.begin(), map.end(), sort_2nd_string);
> sort(map.begin(), map.end(), sort_1st_string);

Sorry, this won't work.  Map iterators are birectional iterators, the sort function requires random-access iterators, and a bidirectional iterator can't take the place of a random-access iterator.
>> Sorry, this won't work.  Map iterators are birectional iterators, the sort function requires random-access iterators, and a bidirectional iterator can't take the place of a random-access iterator.

what if overload the iterator using a wrapper or derived class.
Avatar of healingtao

ASKER

I definitely want one sequence where the ordering takes two strings into account.
So you're saying I should create a key class and have logic like return key1.string1 < key2.string2 ??

but I want key1.string1 to have specific order like I mentioned
1) AAA
2) AA
3) A
4) BBB
5) BB
6) B
7) blank
and also if there is a blank for this string, I want it last as shown above.

How do I do this? because when I don't sort it at all by default the order is
1) blank
2) A
3) AA
4) AAA
5) B
6) BB
7) BBB

Thanks
I forgot to mention that the string previously mentioned is the second part of my key.
The first part should be sorted alphabetically. For example,

String1                                  String2
ABS                                   AAA
ABS                                   AA
ABS                                   A
ABS                                   BBB
ABS                                   BB
ABS                                   B
ABS TOTAL      
AWL                                   AAA
AWL                                   AA
AWL                                   A
AWL                                       BBB
AWL                                       BB
AWL                                       B
AWL TOTAL      

where string1 and string2 is one key

thanks
>>> Sorry, this won't work.  Map iterators are birectional iterators, the sort function requires random-access iterators, and a bidirectional iterator can't take the place of a random-access iterator.

> what if overload the iterator using a wrapper or derived class.

That could be done, but it turns out that sorting in two different sequences is not what the questioner wants, so it's not very relevant at this point.

healingtao,

The usual approach to sorting by two keys is something like this pseudo code:

bool less(key1, key2)
{
  if key1.part1 == key2.part1
    return key1.part2 < key2.part2
  else return key1.part1 < key2.part2
}

You only look at the secondary parts of the keys when the primary parts are equal.

In your case, you would have a more complex test for the secondary parts.

If you know that the empty secondary keys are always with total lines and total lines will be unique, you can ignore empty secondary keys in the sort function, because these lines will always be sorted by their primary keys.

If you do that, the sort logic for the secondary keys could first look at the initial characters of the two keys it is comparing.  If they are different, return a value based on comparing them.  If they are the same, return a value based on comparing their lengths.

--efn
That should have been:

If they are different, return a value based on comparing the initial characters.  If they are the same, return a value based on comparing the lengths of the key strings.
Here is my code for Key class, can you please confirm that I didn't miss anything.
It seems to be working but I'm sure I missed a few things

#if !defined(RISKKEY__INCLUDED_)
#define RISKKEY__INCLUDED_
#include <string>

class RiskKey {
public:
      RiskKey(){}
      RiskKey(std::string strSector, std::string strCreditRating)
      {
            m_strSector = strSector;
            m_strCreditRating = strCreditRating;
      }
      virtual ~RiskKey(){}
      inline const std::string& getSector() const { return m_strSector;}
      inline void setSector(std::string& strSector) {m_strSector = strSector;}
                inline  const std::string& getCreditRating() const { return m_strCreditRating;}
      inline void setCreditRating(std::string& strCreditRating) {m_strCreditRating = strCreditRating;}
      
      friend inline bool operator<(const RiskKey &key1, const RiskKey &key2)
      {
            if (key1.getSector() != key2.getSector())
                  return (key1.getSector() < key2.getSector());
            
            if (key1.getCreditRating() != key2.getCreditRating())
            {
                  if (key1.getCreditRating().substr(0,1) == key2.getCreditRating().substr(0,1))
                  {
                        if (key1.getCreditRating().length() > key2.getCreditRating().length())
                              return true;
                        else
                              return false;
                  }
                  else
                  {
                        return (key1.getCreditRating() < key2.getCreditRating());
                  }
            
            }
      }

private:
      std::string                  m_strSector;
      std::string                  m_strCreditRating;
};

#endif
The only significant problem I see is that the comparison function doesn't deal with the case where the sectors are equal and the credit ratings are equal.  If you know there will not be any such records, I guess that's OK.
efn,

In the case they are equal, do I return true or false?
ASKER CERTIFIED SOLUTION
Avatar of efn
efn

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial