Как сравнить std :: map для работы с несколькими типами данных? - PullRequest
0 голосов
/ 30 марта 2012

Вся таблица хранится в std::deque<record *>, и мне нужно разрешить пользователю сортировать таблицу по любому столбцу. Таблица представляется пользователю в формате списка.

Каждая запись состоит из нескольких строк (структура строк). Однако поля имеют разные типы, то есть время (ЧЧ: ММ: СС), число с плавающей запятой и строки, даже если они все хранятся как строки.

Пользователь может сортировать по любому из этих столбцов. Когда пользователь нажимает на столбец, я сохраняю каждую запись в мультикарте, чтобы таблица отображалась в отсортированном формате для пользователя.

Однако, поскольку столбцы имеют разные типы, как мне написать один метод сравнения, который эффективно обрабатывает все это?

Я подумал о следующих путях

  1. Используйте разные карты для каждого типа и запишите один класс функций сравнения для каждой из карт.
  2. Используйте одну карту с классом сравнения, который обрабатывает все три различных типа. Но для каждой вставки класс сравнения должен решить тип и вставить соответственно.

Есть ли лучший способ, чем эти два?

Пример:

struct ltDataCompare
{

    bool operator()( const CString& csData1, const CString& csData2)  const
    {

        if ( isTimeFormat(csData1) && isTimeFormat(csData1) )
        {
               // Do time relevant comparision
            }
            else if ( isNumberFormat( csTime1 ) && isNumberFormat(csTime2) )
        {
            double dPrice1 = atof((LPCTSTR)csTime1);
            double dPrice2 = atof((LPCTSTR)csTime2);

            return ( dPrice1 < dPrice2);
        }
        return ( csTime1 < csTime2 );
    }
};

std::multimap<CString,list_record_t*,ltDataCompare> _mapAllRecords; // Used only for sorting

Ответы [ 2 ]

1 голос
/ 30 марта 2012

Вы не можете повторно отсортировать map или multimap - после вставки элемента его положение блокируется. Было бы лучше использовать другой контейнер, такой как vector, и сортировать его при необходимости.

Приятной особенностью класса сравнения является то, что ему разрешено содержать состояние. Вы можете иметь член с некоторой константой или указателем, чтобы определить, какой метод сравнения использовать.

Вы можете использовать тот же принцип, чтобы выбрать поле для сортировки.

struct ltDataCompare 
{
    ltDataCompare(int field, int method) : m_field(field), m_method(method) {}
    bool operator()( const record& left, const record& right) const 
    {
        if (m_method == enumTimeFormat)
            return CompareTimes(left[m_field], right[m_field]);
        else if (m_method == enumNumberFormat)
            return CompareNumbers(left[m_field], right[m_field]);
        // ...
    }
    int m_field;
    int m_method;
};

std::sort(table.begin(), table.end(), ltDataCompare(0, enumTimeFormat));
0 голосов
/ 30 марта 2012

Вы могли бы быть более элегантным в этом - я не знаю, вы бы сэкономили себе любую работу - если бы у вас был класс с оператором <для каждого из типов. Если у вас есть суперкласс с виртуальным оператором <, вы можете использовать его в качестве типа ключа, как в </p>

std::multimap< superclass, list_record_t >

Теперь вы можете использовать любой из дочерних типов в качестве фактических ключей (если вы остаетесь последовательными). На самом деле я не уверен, что это умнее или элегантнее. Более умный, как правило, плохая вещь (так как он означает более неясный / менее обслуживаемый). Если это приводит к уменьшению количества строк кода, это, как правило, хорошо.

...