2014-01-13 46 views
4

更新:我遵循约翰的指导,并修改了他的代码,通过创建比较函数解决了我的问题,并将其插入到STL地图中的比较参数中。由于我的字符串日期严格按照显示的格式,使用substr会很好。我的输出和代码仅供参考。STL地图排序

Date   Total Sales 
01JAN1900  $4 
20JAN1902  $40 
18NOV1912  $2500 
19NOV1912  $2500 
19OCT1923  $25 
01JAN1991  $22 
15NOV1991  $300 
Grand Total: $5391 


struct CompareDates 
: 
    public std::binary_function <bool, std::string, std::string> 
{ 
    bool operator() (const std::string& lhs, const std::string& rhs) 
    { 


    if(lhs.substr(5,4) < rhs.substr(5,4)) 
    { 
     return true; 

    } 
    else if (lhs.substr(5,4) == rhs.substr(5,4) && lhs.substr(2,3) < rhs.substr(2,3)) 
    { 
     return true; 
    } 
    else if (lhs.substr(5,4) == rhs.substr(5,4) && lhs.substr(2,3) == rhs.substr(2,3) && lhs.substr(0,2) < rhs.substr(0,2)) 
    { 
     return true; 

    } 
    else 
    { 
     return false; 
    } 


    } 
}; 

map<string, double,CompareDates> dailyDatePrices; 

初始问题:我需要将原始数据分类为日常报告格式。因此,我使用STL map将日期作为关键字和物品价格存储为值。从我读的内容来看,STL地图是自动排序的。不过,我不希望它按照地图进行排序,因为它会生成下面所述的不需要的当前报告输出。我会根据字符串日期进行排序(从最早到最新),并希望它是完全格式。在使用map之前,我已经使用矢量和函数比较器对日期进行了排序。有什么办法可以做到吗?谢谢!

Raw Data 
STRAW:10:15NOV1991 
TOY:10:15NOV1991 
BARLEY:5:01OCT1992 

Undesired Current Report Output 
01OCT1992 5 
15NOV1991 20 

Expected Report Output 
15NOV1991 20 
01OCT1992 5 
+1

使用选择的排序标准实例化映射。 – juanchopanza

+0

你将不得不将字符串转换为日期,并让日期的顺序得到正确的顺序(或使用强的比较器来完成该顺序) - 最好查找日期库 – Mark

+0

你的'日期类定义?该类中具体是'operator <'? – Naveen

回答

1

如果你想要做的是逆向排序地图上它目前使用的,你只要给它一个std::greater比较,而不是默认,std::less

std::map<date, other_type, std::greater<date>> example; 
// Otherwise use example 

实施例:

#include <iostream> 
#include <functional> 
#include <map> 

int main() { 
    std::map<int, float, std::greater<int>> example; 
    example.emplace(std::make_pair(10, 10.0)); 
    example.emplace(std::make_pair(12, 12.0)); 

    for (auto const& entry : example) 
    { 
     std::cout << "Key: " << entry.first << " " << entry.second << std::endl; 
    } 

    return 0; 
} 

http://ideone.com/9Guuil

+0

-1你的答案几乎与问题无关。有趣的是,人们如何盲目地+1 – Slava

+0

@Slava:我不明白它几乎完全不相关。 OP的期望输出和实际输出之间的唯一区别是实际输出的顺序相反。 (s)他没有提供任何其他信息来描述正在发生的事情。约翰的回答(OP只用一个字符串代替适当的日期类型)也是可能的,这就是为什么他从我那里得到+1。 –

+0

是的,您可以正式提供您提供的数据的答案,但很明显,OP要按时间顺序对数据进行排序,而不是盲目地颠倒这两行。所以-1 – Slava

8

std::map排序。没有办法构建未排序的map

问题不在map排序的事实。问题在于你的钥匙是如何设计的。

你说过你的钥匙是日期,但实际上是stringmap如何知道string中的数据实际上是一个日期,并且它应该按照某年的第一个,然后是该月,然后是哪一天排序?它不能。你必须告诉它这样做。

更改键在此格式字符串:

YYYYMMDD

其中YMD都是数字。不要尝试在11月份使用NOV - 请改为使用11。您可以使用unsigned long s代替string s。这会使比较更快,但计算这些值有点棘手。


如果你一定要坚持,因为他们键的原始格式,那么你有一些工作要做。地图根据地图的比较,其被指定为它的一个template parameters排序:

[C++ 03实施例]

struct CompareDates 
: 
    public std::binary_function <bool, std::string, std::string> 
{ 
    bool operator() (const std::string& lhs, const std::string& rhs) 
    { 
    // return true if lhs < rhs 
    // return false otherwise 

    // step 1: compare years. if lhs.year < rhs.year, return true. else, continue 
    // step 2: compare months. if lhs.month < rhs.month, return true. else, continue. 
    // note: don't just compare the strings, else "AUG" < "JAN" etc 
    // step 3: compare days. if lhs.day < rhs.day, return true. else, return false. 
    } 
}; 

由于这似乎是家庭作业,我就让你填写上面的缺失位。:)

使用这种比较对键进行比较,就可以实例化一个地图,做自动正确排序:

std::map <Key, Value, CompareDates> myMap; 
+0

Oooh。没有考虑到这一点。 +1 –

+0

+1如果比较器足够聪明,那么在OP中不需要改变键;比较器可以在仅比较时进行变形。昂贵的,是的,但至少可行。坚实的回答。 – WhozCraig

+0

@WhozCraig:当然可行。尽管如此,这还是很多工作,并且容易出错。如果OP因为任何原因无法更改密钥,那可能是我会做的。 –

1

一条路可走约词汇整理时间数据是将其转换为如下形式:

From: 01OCT1992 
To: 1992-10-01 

现在对于比较字符串的缺省操作<将日期排序工作时,因为更早的日期将永远是按字典少。

0

对我来说,一个明确的设计是定义一个Date类与适当的日/月/年数据成员(和公共访问器,与适当检查字段值,例如检查月份必须在范围1 ... 12等)。

然后,您可以重载operator<定义在Date实例上的正确排序。

然后,你可以简单地有一个std::map<Date, int>(其中int用于存储的价格),事情会简单的工作“开箱即用”,这要归功于正确的分类定义在Date地图键。

如果你想在一个特定的方式格式化日期,你可以定义一个函数,一个Date作为输入,并返回格式化的日期string(这可以在国际化/本地化问题进行修改筑底;我认为这是非常重要的将此输出格式方面与“业务逻辑”分开)。

可编译代码如下(简单地用VS2012测试):

#include <iostream> // for std::cout, std::endl 
#include <map>  // for std::map 
#include <sstream> // for std::ostringstream 
#include <string> // for std::string 
#include <vector> // for std::vector 
using namespace std; 

// A simple date. 
// In real world code, this should be a class with private 
// date members, and proper accessors. 
struct Date { 
    int day; 
    int month; 
    int year; 

    Date() : day(0), month(0), year(0) {} 

    Date(int d, int m, int y) 
     : day(d), month(m), year(y) 
    {} 
}; 

// Define proper sorting for dates 
bool operator<(const Date& d1, const Date& d2) { 
    // First compare years 
    if (d1.year < d2.year) 
     return true; 
    if (d1.year > d2.year) 
     return false; 

    // Same year, compare months 
    if (d1.month < d2.month) 
     return true; 
    if (d1.month > d2.month) 
     return false; 

    // Same year and month, compare days 
    return (d1.day < d2.day); 
} 

// Format dates in a specific format 
string FormatDate(const Date& date) { 
    // NOTE: bounds checking for day and month omitted. 

    ostringstream os; 

    if (date.day < 10) 
     os << '0'; 
    os << date.day; 

    static const char* monthNames[] = { 
     "JAN", "FEB", "MAR", "APR", 
     "MAY", "JUN", "JUL", "AUG", 
     "SEP", "OCT", "NOV", "DEC" 
    }; 
    os << monthNames[date.month - 1]; 

    os << date.year; 

    return os.str(); 
} 

struct Item { 
    string type; 
    int price; 
    Date date; 

    Item(const string& t, int p, const Date& d) 
     : type(t), price(p), date(d) 
    {} 
}; 


int main() { 
    vector<Item> items; 
    items.push_back(Item("STRAW", 10, Date(15, 11, 1991))); 
    items.push_back(Item("TOY", 10, Date(15, 11, 1991))); 
    items.push_back(Item("BARLEY", 5, Date(1, 10, 1992))); 

    map<Date, int> priceData; 
    for (const auto& item : items) { 
     auto where = priceData.find(item.date); 
     if (where != priceData.end()) { 
      where->second += item.price; 
     } else { 
      priceData[item.date] = item.price; 
     } 
    } 

    for (const auto& e : priceData) { 
     cout << FormatDate(e.first) << " " << e.second << endl; 
    } 
} 

输出:

15NOV1991 20
01OCT1992 5