[완료] C++로 데이터 처리관련 질문입니다.
글쓴이: s.choi / 작성시간: 목, 2008/03/20 - 5:44오전
C++ 로 데이터 처리하는 프로그램을 만드려고 하는데요,
간단한 것 같으면서도 잘 안되는 건 왜일까요.. ㅠ.ㅠ
도와주시면 너무 감사드리겠습니다.
아래와 같은 데이터가 있다고 가정해보구요
첫번째 칼럼은 시간,
두번째 칼럼은 특정 값,
세번째 칼럼은 포인터 값을 각각 출력한건데요.
아래 보면, 여러개 포인터 값이 시간순서대로 정렬이 되어 있는데,
이걸 각 포인터별로 시간순서대로 정렬하고픕니다. ㅠ.ㅠ
어떤 방법이 있을까요? 도와주세요~~~~~
아래에는 4개의 서로다른 포인터가 있지만,
최종적으로 토탈 포인터 갯수는 가변적이에요.
(최종 데이터 파일은 첨부 봐주시구요.)
20.000243 357.0 0x86624b8 20.002351 103.0 0x86399f0 20.003571 357.5 0x86624b8 20.005679 103.3 0x86399f0 20.007343 103.7 0x86399f0 20.009007 104.0 0x86399f0 20.010227 358.0 0x86624b8 20.012335 104.3 0x86399f0 20.013999 104.7 0x86399f0 20.016297 1479.7 0x864dfe0 20.017961 1479.7 0x864dfe0 20.018528 666.5 0x86103b0 20.021289 1479.7 0x864dfe0 20.021875 358.5 0x86624b8 20.024617 1479.7 0x864dfe0 20.025203 359.0 0x86624b8 20.027945 1479.7 0x864dfe0 20.028512 667.0 0x86103b0 20.031273 1479.7 0x864dfe0 20.031859 359.5 0x86624b8 20.033504 667.5 0x86103b0 20.036265 1479.7 0x864dfe0 20.036851 360.0 0x86624b8 20.038496 668.0 0x86103b0 20.041257 1479.7 0x864dfe0 20.041843 360.5 0x86624b8 20.043488 668.5 0x86103b0 20.046249 1479.7 0x864dfe0 20.046835 361.0 0x86624b8 20.048499 361.5 0x86624b8 20.051241 1479.7 0x864dfe0 20.051827 362.0 0x86624b8 20.053491 362.5 0x86624b8 20.056233 1479.7 0x864dfe0 20.056819 363.0 0x86624b8 20.059561 1479.7 0x864dfe0 20.060128 669.0 0x86103b0 20.062889 1479.7 0x864dfe0 20.064553 1479.7 0x864dfe0
File attachments:
첨부 | 파일 크기 |
---|---|
![]() | 153.5 KB |
Forums:
3가지 정보가
3가지 정보가 들어가는 구조체 하나 만든담에...
std::vector 같은것에 쭉 집어넣고...
std::sort 함 때려주믄 될듯? 물론 비교 함수는 custom으로 짜셔야죠 ^^
------------------------------------------
Let`s Smart Move!!
http://kalstein.tistory.com/
간단하게 하자면
간단하게 하자면 map의 map을 이용하면되겠네요.
실제론 시간과 값은 소수니까 double이고 포인터는 정수니까 int로 쓰겠지만, 편의상 구분하기위해서 시간의 자료형을 time, 값의 자료형을 value, 포인터의 자료형을 pointer라고 하면
std::map<pointer, std::map<time, value> > values;
정도로 선언하여서 예를 들어 한줄 입력 받았더니 20.000243 357.0 0x86624b8 라고 하면
values[0x86624b8][20.000243] = 357.0;
처럼 값을넣으면 될것 같습니다.
혹시 시간이 중복될수도 있으면 std::map<time, value> 대신에 std::multimap<time, value> 을 이용하시면 되겠구요...
map은 자동으로 정렬되어서 들어가니까, 입력이 끝나면 전부 정렬된 상태일테구요...
대신 인덱스 접근은 안되니까 처음부터 값을 가져올려면 반복자를 쓰셔야겠죠.
아님 다 입력받은 담에 std::vector 등으로 복사하셔도 될테구요.
자료 갯수가 적으면 vector로 넣고 정렬 알고리즘을 이용해도 될텐데 갯수가 많으면 map을 두개 이용하는 방법이 더 빠를것 같습니다.
감사합니다..
음.. 우선 두분 코멘트 감사합니다.
제가 C++ 벡터 사용하는 방법을 몰랐었는데,
이 기회에 한번 공부해보고 프로그램 만들어 봐야겠네요.
완성되면, 여기에 포스팅 할테니 한번 봐주세요. :-)
재차 감사드립니다.
잘 안되네요?? ^_^;;;
아래와 같이 코드를 적어봤는데요...
그 다음 어떻게 해야될지... 도움 주시면 감사드리겠습니다.
(C++ 파일 어태치 했구요...)
#include
#include
#include
#include
#include
using namespace std;
int main (int argc, char *argv[]) {
ifstream fin (argv[1]);
ofstream fout;
string nil, hex;
double time, val;
map > values;
//map >::iterator iter;
if(fin.is_open()) {
while (!fin.eof()) {
fin >> nil;
fin >> nil;
fin >> val;
fin >> time;
fin >> hex;
values[hex][time] = val;
}
fin.close();
} else {
cout << "error opening file!" << endl;
exit (1);
}
int size = values.size();
cout << "size: " << size << endl;
return 0;
}
데이터 화일은 첨부시켰구요..
데이터 화일로 부터 하고자 하는 일은,
각 포인터 값에 따라 각각 다른 파일을 만들고자 하는 일입니다.
첫번째 두번째 컬럼은 그냥 버리는 컬럼이구요,
세번째 컬럼은 특정 값을 나타내는 것이고,
네번째 컬럼은 시간값이고,
다섯번째 컬럼이 포인터 값이에요.
즉, 포인터 값에 따라 시간순서대로 값들을 주욱 정렬하는 일을 하고자 합니다.
도움 주시면 너무너무 감사드릴께요~~~
이제 s.choi님께서하고
이제 s.choi님께서하고 싶은걸 하시면 됩니다. map은 항목을 추가할때마다 정렬되어서 들어가있기 떄문에 이미 정렬은 끝나있는 상태입니다.
예를 들어 포인터와 시간 순서대로 값을 출력하고 싶다면
이런식이되겠죠.
한가지만 더 문의드릴께요~
감사합니다! 도와주신 덕분에 기본적인 문제는 해결 되었습니다.
다만, 포인터에 별로 결과값을 다른 파일에 저장을 하고 싶은데, 이 부분을 어떻게 하는지 혹시 좋은 방법 알고 계시면 한수만 더 배워보고 싶습니다.
제가 완성한 코드는 첨부로 넣었구요...
(데이터 파일은 위의 foo.txt 파일을 그대로 사용하고자 합니다.)
다시한번 도움에 깊은 감사드립니다!!
:-)
음...왠지 map이 '연관
음...왠지 map이 '연관 컨테이너'라는 것을 이해하고 못하고 계신느낌이 드는데요(아니라면 죄송합니다), stl을 소개하고 있는 책이나 인터넷에서 간단하게라도 살펴보시는게 좋을 것 같습니다.
cout 대신에 fout을 쓰는 정도외에는 똑같습니다. 예를 들면
힌트 너무 감사드립니다.
아마도 제가 확실하게!! 이해하지 못했던 부분이 있엇던 것 같습니다. 인터넷 자료와 책을 참고하여 map 에 대해서 다시 살펴보았습니다. 그런데, 제가 추가로 질문드린 부분은 map 부분이라기 보다는 file stream 에 관련된 부분이 아닌가 싶습니다. (아니면 스트링?? ㅠ.ㅠ)
즉, 결과값을:
result_1.xg
result_2.xg
result_3.xg
.
.
.
이런식 파일네임으로 개별 저장하고 싶어서 아래와 같이 수정하여 보았는데, 한 부분에서 에러가 나고 있는데, 이유를 잘 모르겠습니다. 어떻게 해야할지 힌트 주시면 너무 감사드릴께요. (지금껏 제 질문 쓰레드에 친절히 답변해 주셔서 너무 감사감사 드리고 있어요...) 많은 도움이 되었습니다.
여러가지 네트워크 실험을 하면서 얻은 결과치를 서로 다른 파일에 저장하고 gnuplot 으로 플로팅해서 성능 비교 분석 평가하는 일들을 하다가 발생한 일인데, 혼자서 해결하지 못하다가 xylosper 님 도움 받아가면서 거의 다 해결 한 듯 합니다.
고맙습니다~
다음과 같이 삽질 해봤는데요....
이리저리 찾아보니까 integer 를 string 으로 type cast 하는 방법을 알아봤는데요, std::stringstream 을 이용하는 방법이 있더군요. 그래서 아래와 같이 삽질을 해 봤는데, result_1.xg 까지는 잘 나오는데, 그 다음이 안만들어지는건 정말 왜 그런지...
참, 간단한것 같은데, 속 썩이네요. ㅠ.ㅠ
어디가 잘못 된건지 한번 봐주시면 고맙겠습니다.
이 코드로 위의 foo.txt 돌리면
result_1.xg 화일 하나 밖에 안만들어져요... ㅡ.ㅡ;;;
stringstream sstr 을....
음...
이 부분을 for loop 안으로 집어 넣으니까 되네요...
휴~ 참으로 긴 시간동안 답변 달아주시고 관심 가져주셔서 감사합니다.
근데, 저 부분을 stringstream 말고 좀더 elegant 한 방법으로 처리하는 방법은 없을까요? 후후~
아무튼 xylosper 님의 개인시간 많이 뺐어서 너무 죄송하고, 그 동안 답변 큰 도움 되었습니다.
다시한번 감사드립니다.
최종 버젼 입니다.
그 동안 수 차례에 걸쳐서 xylosper 님의 힌트를 받고서 아래와 같은 프로그램을 작성하게 되었습니다.
원하는 일은, 본 쓰레드 위쪽에 있는 foo.txt 파일을 가지고,
서로다른 포인터가 가지는 값을 각각 result_1.xg, result_2.xg, result_3.xg, result_4.xg 와 같은 파일로 따로 분류/저장 하고자 하는 일입니다. 처음에는 간단하게 awk 으로 해 보려고 했는데, 포인터가 딱 4개 혹은 8개 씩 정해진게 아니라, 어떨때는 100개도 될 수 있고, 어떨때는 2개도 될 수 있고 등등 포인터가 몇개가 될지 모르는 상황이구요... 그 개별 포인터 별로 시간별로 특정 값을 주우우욱 가지게 되는 결과파일이 바로 foo.txt 입니다.
이 일을 해결 하는데 있어서 핵심 내용은 C++의 map 을 이용하는 것이었고, 여기서는 map of map 을 이용했습니다.
라고 실행하면,
result_1.xg
result_2.xg
result_3.xg
result_4.xg
.
.
.
와 같이 결과치를 분류해서 저장하게 됩니다.
그럼 코드는
이렇게 되었습니다. 자세한 내용은 코드 안에 커멘트로 달아두었습니다.
첨부로 코드를 붙입니다.
코드를 잘 만들어서 공개하는 것이 절대!!!! 아닙니다.
혹시 저와 비슷한 일로 괜히 시간 뺐기지 마시라고 올려둡니다.
(물론 여기 고수님들께선 이런일로 시간 별로 안 뺐기시겠지만... ㅡ.ㅡ;;;)
다시한번 xylosper 님께 감사드리구요, 다른 커멘트 있으시면 환영!! 합니다. :-)
이상입니다.
기왕 stringstream을
기왕 stringstream을 쓰신다면 그냥 그걸 계속 쓰시는게 좋지 않을까요?
대신에
그리고 string에 string은 덧붙일때는 char *로 꺼낼 필요가 없습니다. str[i].append(option.c_str()) 보다는 str[i].append(option)으로 충분하고, 연산자 오버로드도 되있으니까 보통은 str[i] += option 처럼 쓰죠...
반복해서죄송합니다만, STL에 대해서 알고리즘까진 안보더라도 string이나 vector같은 컨테이너들에 대한 사용법정도는 훓어보시는게 좋을 것 같습니다.
아~~~~
그런 방법이 있었군요.. string stream 을 사용하면 integer 를 따로 string 으로 바꿀 필요도 없어지겠네요...
이렇게 시간 내 주시고 친절히 알려주셔서 감사합니다.
STL 사용법을 보긴 했는데, 너무 대충 봤나봐요.. 다시한번 꼼꼼이 살펴보겠습니다.
^_^
꾸벅~
수고하셨습니다.
수고하셨습니다. :-)
몇 가지 말씀드리죠.
1. input file stream의 사용법
while loop의 탈출 조건으로 eof()를 쓰는 것은 올바른 방법이 아닙니다.
loop 내부에 입력된 값을 cout으로 출력하는 루틴을 넣어보면 마지막 줄을 두 번 읽는 것처럼 보일 것입니다.
그런데 map에 저장하면서 이것이 묻혀버린 것이죠.
대부분의 경우 eof()는 사용할 필요가 없고 다음과 같은 방법으로 족합니다.
그리고 파일로부터 직접 값을 입력받는 것은 별로 안전한 방법이 아닙니다.
중간에 잘못된 내용이 있으면 그 이후의 입력은 모두 잘못되니까요.
보통은 다음과 같이 string으로 한 줄을 읽은 후 istringstream으로부터 입력받습니다.
그러면 잘못된 내용이 있는 줄만 건너뛰고 그 다음은 계속 정상적으로 진행할 수 있습니다.
2. string str의 선언
이것은 표준 C++ 코드가 아닙니다. 배열 크기는 컴파일 타임에 정해지는 상수이어야 하는데
size는 런타임에야 알 수 있으니까요. 이 코드는 gcc의 확장기능에 의존하므로 이식성이 없는 것입니다.
사실 이 경우에는 str을 배열로 선언할 필요도 없어보입니다.
3. 숫자를 string으로 바꾸는 법
기본적으로는 지금 하신 것처럼 stringstream을 이용합니다.
그런데 이것이 좀 번거롭죠. 이럴 때 쓰기 위해 boost라는 라이브러리에서 lexical_cast라는 함수를 제공합니다.
이 역시 stringstream으로 구현한 것입니다.
template으로 되어 있어 operator >>, operator << 가 정의된 형끼리는 자유롭게 변환할 수 있습니다.
ps. 쓰고 나서 보니까 3번은 xysloper님이 말씀하신 방법이 훨씬 나아 보이는군요.
인용: 이 코드는 gcc의
아마 g++ 라고 말하려고 했던 것 같습니다. C에서는 표준이니까요.
으아아아~~~
너무너무 x 3000 감사드려요...!! 특히, 1번과 2번 항목은 많이 도움되었어요.. 사실 저도 eof()를 while 문과 같이 쓰면서 제일 마지막 줄이 두번 출력되는 문제가 왜 그렇게 된건지 이해를 못하고 있었거든요.. 이제 뭔가 더 클리어하게 알게 된 것 같습니다.
스트링 배열 선언을 제가 한대로 하고서 -Wall 옵션으로 컴파일하면 warning message 가 뜨더라구요. 그래도 일단 컴파일은 됐었던 거라거 무시하고 있었는데, C++ 의 정석은 그 방법대로 하면 안되는 것이었군요??
제 코드를 xylosper 님과 그리고 doldori 님의 말씀대로 수정하였습니다.
완성된 코드와 샘플 trace file을 제일 아래에 올려두겠습니다.
xylosper 님, 그리고 마지막에 좋은 힌트 주신 doldori 님께 다시한번 감사드립니다. :-)
질문하는 김에
질문하는 김에 한가지만 더 여쭤볼께요...
말씀하시기로는, 아래 코드면 충분 하다고 하셨는데,,,,,
만약, input 파일에 오류가 생겨서, 원래는 5개의 값이 input 으로 들어와야 되는데, 뭐 4개 값만 들어왔다던지, 아니면 6개 값이 들어왔다고 하면.... 그에 해당하는 input 은 받지 않는 방법이 있을까요?
도움말씀 감사드립니다~
doldori님께서 그래서
doldori님께서 그래서 바로 읽어들이기보다는 getline을 이용해서 한줄씩 읽어서 변수로 넣는 예도 적어주셨습니다.
네, getline 으로
네, getline 으로 한줄씩 읽는 것은 맞는데, 한줄에 4가지 아이템이 있는지 혹은 6가지 아이템 (혹은 그 이상)이 있는지를 판별 해주지는 못하더라구요.
아래의 부분 코드에서 말인데요...
getline 으로 읽기는 읽었는데, 저는 정확히 5가자 아이템이 있는 라인만 input 으로 받고 싶거든요... 위의 코드로는 6개의 아이템 이런 라인도 입력이 되고 이상하게 꼬이고 그러더라구요??
그런 경우라면
그런 경우라면 읽어들인 라인을 파싱하는 수밖에 없을 듯합니다.
s.choi님의 경우라면 읽어들인 sline을 공백문자로 쪼개준후, 갯수를 체크하거나 추가로 필요한 것을 체크한다음 valid한 데이터만 기록하도록요...
그쵸... ^_^ 제가 바로
그쵸... ^_^ 제가 바로 그 짓을 하려고 하는데... "공백문자로 쪼개서 하나하나씩 인풋 시키는 작업"
방법을... 잘..... ㅠ.ㅠ
C++ 시작한지가 얼마 안되나서 내공이 많이 부족합니다.. ㅡ.ㅡ;;
이미 공백문자로
이미 공백문자로 쪼개서 넣는 것을 하고 계십니다.
istringstream 으로 읽고 있으니까요.
예를 들어 갯수만 검사하면 된다면
이런식으로 하면되겠죠.
xysloper님의 말씀처럼
xysloper님의 말씀처럼 공백을 기준으로 파싱할 수도 있고
다음과 같은 방법도 생각할 수 있겠습니다.
한 줄에 반드시 2개의 데이터만 있어야 할 경우
sentry의 역할은 2개의 데이터를 읽은 후 그 뒤에 공백문자 이외의 내용이 있는지 검사하는 것입니다.
유효한 데이터라면 sentry의 입력은 실패해야 하는 것이지요.
그냥.
참고 삼아 드리는 말씀인데
sort +2 poo.txt > poo.new.txt
로 하면 안되는 것인가요?
포인터 별로 나누는 건 다시 생각하더라도 말이지요.
--
기왕 하는 거 나누는 거 까지
sort +2 poo.txt > poo.sorted.txt ; for i in `sort -u +2 poo.txt | awk '{print $3}'` ;do egrep $i poo.sorted.txt > $i.result ;done
-------------------------------
인생 뭐 있음!
-------------------------------
== warning 대부분 틀린 얘기입니다 warning ===
헉!
이런 방법도 있군요!!! ^_^
컴터는 배우면 배울수록 즐겁습니다.
좋은 방법인것 같아요~ 감사합니당~~
최종버젼 (special thanks to xylosper, doldori)
간단한 것 같았는데 이리저리 해보다보니 여러가지 기본적인 것들을 많이 놓치고 있었구나 라는 생각이 들었습니다. 그 동안 친절하게 답해주신 xylosper 님께 다시한번 감사드리구요, 마지막에 doldori 님의 기본적인 input file stream, string declaration 에 관한 힌트도 큰 도움이 되었습니다!!
input file은 바로 아래 첨부에 있는 foo.txt 입니다. 코드는 아래에 붙여두겠습니다.
이상입니다~~~!!
:-)
최종 ( 입력 필드 갯수까지 sanity check 가능)
또다시 xylosper님, doldori 님 감사드립니다.
처음에는 _매우_ 간단한 작업인줄 알았는데, 솔찬히 많이 배우고 갑니다. :-)
xylosper 님께서 주신 힌트를 이용하여, 입력 필드값 갯수가 정확히 n 개 일때만 map 에 저장하는 기능을 추가하였습니다. 이 기능이 필요했던 이유는, 입력 파일에 간간히 오류가 섞인 데이터가 포함될 수 있는데, 이렇게 되면 8개의 포인터가 가지는 값을 8개의 서로다른 파일로 저장하는데에 있어서 문제가 발생했습니다. C++의 map 이 데이터를 처리할때 오류가 섞인 line의 필드값까지 map에 집어넣어버려서 실제로는 원하는 8개의 map 이 생기는게 아니라 9개도 생겼다가 10개도 생겼다가 자기 맘대로 되버리는 일이 발생 했기 때문입니다. 따라서, 각 입력 line당 정확히 원하는 필드의 갯수가 있는 line 만 map에 집어 넣기를 원했습니다.
완성된 코드는 ....
여기 링크에서 보실 수 있습니다.
(아래에 cut & paste 해두었구요)
이렇게 되었습니다.
바뀌어진 부분은, input string stream 을 vector 에 집어넣고, 그 벡터의 사이즈가 원하는 사이즈 일때 (즉, n 개의 element) 일때에만 원하는 작업을 하도록 수정했습니다. 저~~~ 위에 xylosper 님께서 pseudo code 형식으로 적어주신 대로 그대로 하니까, 결과의 차이가 없더라구요. 그래서 vector 에 집어 넣었다가, 일일이 다시 끄집어 내고, 그걸 다시 tmp 라는 string stream 으로 집어 넣어주는 형식으로 만들어 봤습니다.
휴!!!!
고수님들한테는 이런거 하는게 몇십분 정도면 될 일을,,,, 저 혼자서 몇일을 고생했네요...
그래도 xylosper 님과 doldori 님 도움 없었으면, 아마 아직도 헤딩하고 있었을꺼에요... 흑흑~~~~
이제는 정말 final version 이겠죠?? ㅎㅎㅎ
감사합니다!!
댓글 달기