データの並べ替えについて – 固定ページ 3 – プログラミング – Home

データの並べ替えについて
 
通知
すべてクリア

[解決済] データの並べ替えについて

固定ページ 3 / 3

επιστημη
 επιστημη
(@επιστημη)
ゲスト
結合: 22年前
投稿: 1301
 

ということは、最後まで読んでみないことには出力すべき行が確定しないてことね。
...それで何が問題なのでしょうか?
codeごとに最新日付の行を最大5つをメモリ内に残しておくだけですが。
メモリが許すならとにかく全部蓄え、出力の際に最大5つに抑えてもいい。


返信引用
επιστημη
 επιστημη
(@επιστημη)
ゲスト
結合: 22年前
投稿: 1301
 

> メモリが許すならとにかく全部蓄え、出力の際に最大5つに抑えてもいい。

#include <iostream>
#include <sstream>
#include <string>
#include <queue>
#include <map>

using namespace std;

int main() {
map<std::string,priority_queue<string> > m;
istringstream input(
20070831,0101,i,16270,16569,16266,16569,1840060000\n
20070830,0101,i,16182,16269,16091,16153,1523490000\n
20070829,0101,i,16068,16068,15830,16012,1691410000\n
20070828,0101,i,16214,16343,16192,16287,1331870000\n
20070827,0101,i,16429,16504,16263,16301,1471220000\n
20070824,0101,i,16286,16329,16188,16248,1592040000\n
20070823,0101,i,16093,16333,16093,16316,1805960000\n
20070822,0101,i,15866,15957,15787,15900,1661020000\n
20070821,0101,i,15773,16101,15754,15901,2035260000\n
20070820,0101,i,15477,15940,15477,15732,2244960000\n
20070831,0201,i,1575,1608,1574,1608,1840060000\n
20070830,0201,i,1574,1579,1560,1568,1523490000\n
20070829,0201,i,1562,1562,1537,1557,1691410000\n
20070828,0201,i,1578,1591,1576,1584,1331870000\n
20070827,0201,i,1602,1610,1584,1587,1471220000\n
20070824,0201,i,1587,1591,1578,1585,1592040000\n
20070823,0201,i,1562,1591,1562,1591,1805960000\n
20070822,0201,i,1547,1550,1536,1544,1661020000\n
20070821,0201,i,1532,1565,1531,1549,2035260000\n
20070820,0201,i,1500,1544,1500,1523,2244960000\n
20070817,0201,i,1557,1561,1479,1480,2942470000\n
20070816,0201,i,1576,1576,1529,1567,2676800000\n
20070831,1301,t1,208,213,208,213,238000\n
20070830,1301,t1,211,211,208,208,129000\n
20070829,1301,t1,210,210,207,209,226000\n
20070828,1301,t1,211,213,211,213,234000\n
20070827,1301,t1,209,214,207,210,611000\n
20070824,1301,t1,208,209,207,208,141000\n
20070823,1301,t1,205,208,204,207,227000\n
20070822,1301,t1,205,206,202,202,322000\n
20070821,1301,t1,203,208,203,205,271000\n
20070820,1301,t1,207,209,202,203,432000\n
20070817,1301,t1,206,207,200,200,605000\n
20070816,1301,t1,210,210,205,209,596000\n
20070815,1301,t1,213,213,211,211,217000\n
20070831,1401,t1,2,2,2,2,238000\n);
string line;
while ( getline(input,line) ) {
m[line.substr(9,4)].push(line);
}
for ( map<std::string,priority_queue<string> >::iterator iter = m.begin();
iter != m.end(); ++iter ) {
for ( int i = 0; i < 5 && !iter->second.empty(); ++i ) {
cout << iter->second.top() << endl;
iter->second.pop();
}
}
}


返信引用
ソイレントグリーン
 ソイレントグリーン
(@ソイレントグリーン)
ゲスト
結合: 17年前
投稿: 65
Topic starter  

お世話になります
>メモリが許すならとにかく全部蓄え、出力の際に最大5つに抑えてもいい。
はい、その方向でお願い致します。

コードのご教示ありがとうございます、istringstream型というものを始めてみました。

WEBで色々検索して、istringstream型とはchar型についてbasic_istringstreamクラスを
インスタンス化したものです。という記述を見かけたのですが、この度ファイルからデー
タをistringstream型のinputに食わせる場合、下記のようにしたのですが、inputをトレ
ースしてみたのですが、空(null)しか表示されません使い方が間違っていますでしょう
か?

HANDLE hFile=::CreateFile(m_FileName,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,NULL);

if(hFile == INVALID_HANDLE_VALUE)
throw ファイルハンドルの取得に失敗しました;

DWORD dwFileSize = GetFileSize(hFile , NULL);
char* pBuff = new char[dwFileSize + 1 ];

DWORD dwResult;
::ReadFile(hFile, pBuff, dwFileSize, &dwResult, NULL);
::CloseHandle(hFile);
*(pBuff + dwFileSize) = '\0';

map<std::string,priority_queue<string> > m;
istringstream input(pBuff);

string line;
while ( getline(input, line) ) {
TRACE(%s, line);
m[line.substr(9,4)].push(line);
}

for ( map<std::string,priority_queue<string> >::iterator iter = m.begin();
iter != m.end(); ++iter ) {
for ( int i = 0; i < 5 && !iter->second.empty(); ++i ) {
TRACE(%s, iter->second.top());
cout << iter->second.top() << endl;
iter->second.pop();
}

}


返信引用
επιστημη
 επιστημη
(@επιστημη)
ゲスト
結合: 22年前
投稿: 1301
 

...なにわざわざめんどくせーことやってんだろってのが正直な感想。

#include <sstream>
istringstream input(....); を

#include <fstream>
ifstream input(ファイル名); に取り換えるだけです。


返信引用
ソイレントグリーン
 ソイレントグリーン
(@ソイレントグリーン)
ゲスト
結合: 17年前
投稿: 65
Topic starter  

επιστημηさん、ありがとうございます、お陰さまで動くものができました。
しかしちょいと問題があります。
下記のソースですと一年分のデータ49.4 MB 1,326,859行のデータを処理するのに、約100
分程度の時間がかかってしまいます。
先に掲示したソースだと、同じファイルで処理を行っても2分程度で終わります。
やはり速度を稼ぐには、ディスクアクセスの部分は生のWin32APIを叩いたほうがよさげか
な?
これから実験してみます。

map<std::string,priority_queue<string> > m;

ifstream input(m_FileName);
ifstream ofs;
string line;
while ( getline(input, line) ) {
m[line.substr(9,4)].push(line);
}
for ( map<std::string,priority_queue<string> >::iterator iter =
m.begin();
iter != m.end(); ++iter ) {
for ( int i = 0; i < 250 && !iter->second.empty();
++i ) {
std::ofstream ofs( iter->first.c_str(),
std::ios::out | std::ios::app );
ofs << iter->second.top() << std::endl;
iter->second.pop();
}
}


返信引用
επιστημη
 επιστημη
(@επιστημη)
ゲスト
結合: 22年前
投稿: 1301
 

時間の掛かっているのは読みですか? 書きですか?

for ( int i = 0; i < 250 && !iter->second.empty(); ++i ) {
std::ofstream ofs( iter->first.c_str(), std::ios::out | std::ios::app );
ofs << iter->second.top() << std::endl;
iter->second.pop();
}

ループの中でファイルのopen/closeを繰り返しているのには理由がありますか?


返信引用
ソイレントグリーン
 ソイレントグリーン
(@ソイレントグリーン)
ゲスト
結合: 17年前
投稿: 65
Topic starter  

今日はεπιστημηさんソイレントグリーンです
>時間の掛かっているのは読みですか? 書きですか?
殆ど書き込みに時間がかかっています。
>ループの中でファイルのopen/closeを繰り返しているのには理由がありますか?
最終的に、コード毎のファイルを作成(約4000)が目的なので、コード名が変化した時点
で、ファイルを作成する必要があるからなのですが。


返信引用
επιστημη
 επιστημη
(@επιστημη)
ゲスト
結合: 22年前
投稿: 1301
 

>>ループの中でファイルのopen/closeを繰り返しているのには理由がありますか?
> 最終的に、コード毎のファイルを作成(約4000)が目的なので、
> コード名が変化した時点で、ファイルを作成する必要があるからなのですが。

そのループ内で iter->first は変化していますか?


返信引用
麩
 麩
(@麩)
ゲスト
結合: 17年前
投稿: 95
 

高速化の例として「ループ外で出来る処理はループ外でしてしえ」って物がありま
すが、まさにそれですね。
結構いろいろな場所でこの高速化はできるので、高速化したい場合はそういう
お決まりのセオリーを幾つか知っておくと便利です。


返信引用
ソイレントグリーン
 ソイレントグリーン
(@ソイレントグリーン)
ゲスト
結合: 17年前
投稿: 65
Topic starter  

επιστημηさん、麩さんお世話になります。
>そのループ内で iter->first は変化していますか?
250回に一回しかpair値のfirst変数は変わんなかったんでしたね(^^;
そりゃー百万単位、毎回毎回I/O操作してたら遅くなりますね。

>お決まりのセオリーを幾つか知っておくと便利です。
ごもっともです、なんかプログラムが期待した振舞いをしてくれなかったりすると
基本的なセオリーとかスコーンと見失って、見当違いな観点で他に原因を探して、
結局遠回りしてしまうんですよね。
for ( map<std::string,priority_queue<string> >::iterator iter = m.begin();
iter != m.end(); ++iter ) {
std::ofstream ofs( iter->first.c_str(), std::ios::out |
std::ios::app ); for ( int i = 0; i < 250 && !iter->second.empty();
++i ) {
ofs << iter->second.top() << std::endl;
iter->second.pop();
}
}
これで、速度も解決できました色々お世話になりました。

後一点お聞きしたいのですが、今回επιστημηさんがマップによる、配列の操作をご教示
して下さったのですが、
特に私が着目したのはイテレータのサブ関数である
iter->second.empty()と
iter->second.pop()
です、この方法が見いだせなくて頭を抱えていました、前回FUKUさんがご教示してくださ
ったvectorの場合、このような配列の要素をpair値では扱えないのでしょうか、また無い
場合vectorで、それに変わる手法はございませんでしょうか?


返信引用
επιστημη
 επιστημη
(@επιστημη)
ゲスト
結合: 22年前
投稿: 1301
 

empty()/pop()はmapとは関係ありません。
mapの要素となっている priority_queue のメンバです。


返信引用
επιστημη
 επιστημη
(@επιστημη)
ゲスト
結合: 22年前
投稿: 1301
 

priority_queueのかわりにvectorを使った例。
その分ちょびっと遅くなります。

#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>

using namespace std;

int main() {
map<string,vector<string> > m;
istringstream input(
20070831,0101,i,16270,16569,16266,16569,1840060000\n
20070830,0101,i,16182,16269,16091,16153,1523490000\n
20070829,0101,i,16068,16068,15830,16012,1691410000\n
20070828,0101,i,16214,16343,16192,16287,1331870000\n
20070827,0101,i,16429,16504,16263,16301,1471220000\n
20070824,0101,i,16286,16329,16188,16248,1592040000\n
20070823,0101,i,16093,16333,16093,16316,1805960000\n
20070822,0101,i,15866,15957,15787,15900,1661020000\n
20070821,0101,i,15773,16101,15754,15901,2035260000\n
20070820,0101,i,15477,15940,15477,15732,2244960000\n
20070831,0201,i,1575,1608,1574,1608,1840060000\n
20070830,0201,i,1574,1579,1560,1568,1523490000\n
20070829,0201,i,1562,1562,1537,1557,1691410000\n
20070828,0201,i,1578,1591,1576,1584,1331870000\n
20070827,0201,i,1602,1610,1584,1587,1471220000\n
20070824,0201,i,1587,1591,1578,1585,1592040000\n
20070823,0201,i,1562,1591,1562,1591,1805960000\n
20070822,0201,i,1547,1550,1536,1544,1661020000\n
20070821,0201,i,1532,1565,1531,1549,2035260000\n
20070820,0201,i,1500,1544,1500,1523,2244960000\n
20070817,0201,i,1557,1561,1479,1480,2942470000\n
20070816,0201,i,1576,1576,1529,1567,2676800000\n
20070831,1301,t1,208,213,208,213,238000\n
20070830,1301,t1,211,211,208,208,129000\n
20070829,1301,t1,210,210,207,209,226000\n
20070828,1301,t1,211,213,211,213,234000\n
20070827,1301,t1,209,214,207,210,611000\n
20070824,1301,t1,208,209,207,208,141000\n
20070823,1301,t1,205,208,204,207,227000\n
20070822,1301,t1,205,206,202,202,322000\n
20070821,1301,t1,203,208,203,205,271000\n
20070820,1301,t1,207,209,202,203,432000\n
20070817,1301,t1,206,207,200,200,605000\n
20070816,1301,t1,210,210,205,209,596000\n
20070815,1301,t1,213,213,211,211,217000\n
20070831,1401,t1,2,2,2,2,238000\n);
string line;
while ( getline(input,line) ) {
m[line.substr(9,4)].push_back(line);
}
for ( map<string,vector<string> >::iterator iter = m.begin();
iter != m.end(); ++iter ) {
vector<string>& lines = iter->second;
for ( int i = 0; i < 5 && !lines.empty(); ++i ) {
swap(*max_element(lines.begin(),lines.end()),lines.back());
cout << lines.back() << endl;
lines.pop_back();
}
}
}


返信引用
ソイレントグリーン
 ソイレントグリーン
(@ソイレントグリーン)
ゲスト
結合: 17年前
投稿: 65
Topic starter  

επιστημηさん、皆さん最期まで、丁寧に御回答いただき大変ありがとうございました。
まだまだお聞きしたいことは沢山ありますが、STLに関してもう少し私自身、学習してか
らに致します。

余談ですが、
この度、「STL標準講座―標準テンプレートライブラリを利用したC++プログラミング
(Programmer’s SELECTION)」と「Effective STL―STLを効果的に使いこなす50の鉄則」
という2冊の書籍をamazonに注文しているのですが

「STL標準講座―標準テンプレートライブラリを利用したC++プログラミング
(Programmer’s SELECTION)」
ハーバート シルト (著), Herbert Schildt (原著), 多摩ソフトウェア (翻訳), エピス
テーメー
(翻訳), エピステーメーとありますが、今わたくしに回答していただいている
επιστημηさんなのでしょうか?
差し障りがあれば別にお返事していただくとも、結構です適当にスルーしてください。
いづれにせよ、何処のどなたか分かりませんが、STLの素晴らしいさを、見せていただき
大変お世話になりました。
ありがとう。


返信引用
επιστημη
 επιστημη
(@επιστημη)
ゲスト
結合: 22年前
投稿: 1301
 

はい、監修をやらせてもらいました。


返信引用
固定ページ 3 / 3

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました