2014-01-13 48 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