본문 바로가기
프로그래밍/C++

C++ ] 교통사고 통계자료 필터 프로그램 (2) - vector 사용 , 파입입출력

by eteo 2022. 6. 28.

깃허브 주소 : https://github.com/joeteo/CarAccident

 

 

 

 

main.cpp

#include <iostream>
#include "AccidenData.h"
#include "AccidentList.h"
#include <Windows.h>
enum
{
	PRINTLIST = 1,
	SUBTOTAL,
	EXIT
};
using namespace std;

int main()
{	
	AccidentList handler;

	handler.readListFromFile();

	while(1)
	{	
		system("cls");
		int select;
		handler.DispMenu();
		cin >> select;

		switch(select)
		{
		case PRINTLIST:
			handler.searchList();
			break;
		case SUBTOTAL:
			handler.SearchSubTotal();
			break;
		case EXIT:
			handler.deleteAll();
			return 0;
		default:
			cin.clear();
			cin.ignore(1000, '\n');
			cout << endl << "잘못 누르셨습니다. 다시 선택해 주세요." << endl;
			Sleep(300);
			break;
		}
	}
	return 0;
}

 

case EXIT 종료 직전에 동적할당받았던 것을 모두 해제하는 deleteAll() 함수를 추가했다.

 

 

 

AccidentList.h

#pragma once
#include "AccidenData.h"
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <iostream>
using namespace std;

class AccidentList
{
private:
	vector<AccidentData*> list;

public:
	AccidentList();

	void DispMenu();
	void printTitle();
	void printSubject();
	void readListFromFile();
	void printRow(int i);
	void printAll();
	void searchList();
	void SearchSubTotal();
	void SaveListToFile(string Keyword, vector<int> searchedRow);
	void SaveSubTotalToFile(string Keyword, string subTotalStr);
	string MakeRowToStr(int i);
    void deleteAll();

	~AccidentList(){};
};


포인터 배열로 사용하던 부분을 AccidentData*타입 vector로 바꾸었다.

 

vector는 가변길이의 배열이라고 할 수 있다.

 

데이터를 추가할 때는 vector명.push_back(데이터) 로 하고 뒤에 차곡차곡 들어간다.

접근할때는 vector명.at(i) 로 하고, 길이를 구할 땐 vector명.size() 로 한다.

데이터를 지울 때는 vector명.erase(iterator) 로 지운다. 지운 인덱스의 바로 다음 인덱스부터 마지막 인덱스까지는 앞으로 한칸 씩 땡겨진다.

 

사용시 마치 배열을 사용하듯 하면서 가변적이고 제공함수가 많아서 편리하게 쓸 수 있다.

 

 

 

 

AccidentList.cpp

#include "AccidentList.h"
#include "AccidenData.h"
#include <stdio.h>
#include <Windows.h>
#include "AccidenData.h"


AccidentList::AccidentList()
{}

void AccidentList::printTitle()
{
	cout << "=================== 교통사고 통계 검색 프로그램 ===================" << endl << endl;
}

void AccidentList::DispMenu()
{
	cout << "=================== 교통사고 통계 검색 프로그램 ===================" << endl << endl;
	cout << "키워드 검색 후 실행할 메뉴를 선택해주세요." << endl<< endl;
	cout << " 1. 리스트 보기" << endl << endl;
	cout << " 2. 부분합 보기" << endl << endl;
	cout << " 3. 종료" << endl << endl;
	cout << "선택: [_]\b\b";
}

void AccidentList::readListFromFile()
{
	ifstream data("ANSIData.csv");
	string line;

	int i = 0;

	while (getline(data, line))
	{
		stringstream linestream(line);
		string cell[COLUMN_NUMBER];
		for (int j = 0; j < COLUMN_NUMBER; j++)
		{
			getline(linestream, cell[j], ',');
		}
		list.push_back(new AccidentData(cell[0], cell[1], &cell[2]));
		i++;
	}
}

void AccidentList::printSubject()
{
	printf("시도,시군구,터널안,교량위,고가도로위,지하차도(도로)내,기타단일로,교차로내,교차로횡단보도,교차로부근,철길건널목,기타,불명\n");
}

void AccidentList::printRow(int i)
{
	cout << list.at(i)->GetSiDo() << "," << list.at(i)->GetSiGunGoo() << ",";

	for (int j = 0; j < LOCATION_NUMBER; j++)
	{
		cout << *(list.at(i)->GetAccidentCount() + j);
		if (j != LOCATION_NUMBER - 1)
		{
			cout << ",";
		}
	}
	cout << endl;
}

void AccidentList::printAll()
{
	printSubject();
	for(int i=0; i<list.size();i++)
	{		
		printRow(i);
	}
}

void AccidentList::searchList()
{
	system("cls");
	printTitle();
	string keyword;
	cout << "검색어를 입력하세요 (시도 또는 시군구) ..... [                        ]\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";	
	cin >> keyword;
	int chk=0;
	cout << endl;

	vector<int> searchedRow;

	for(int i=0; i<list.size();i++)
	{
		if(keyword.compare(list.at(i)->GetSiDo())==0)
		{
			printRow(i);			
			chk++;

			searchedRow.push_back(i);
		}
	}

	if(chk==0)
	{
		for (int i = 0; i < list.size(); i++)
		{
			if (keyword.compare(list.at(i)->GetSiGunGoo()) == 0)
			{
				printRow(i);

				searchedRow.push_back(i);
			}
		}
	}

	cout << endl;

	int choose = 0;
	cout << "검색 결과를 파일로 저장하시겠습니까? [ 1.예 / 2.아니오 ]" << endl << endl;
	cout<<"선택 : [_]\b\b";
	cin >> choose;
	if(choose==1)
	{
		SaveListToFile(keyword, searchedRow);
	}else if(choose==2)
	{
		cout << "메뉴로 돌아갑니다..." << endl;
		Sleep(500);
	}
}

void AccidentList::SearchSubTotal()
{
	system("cls");
	printTitle();
	string keyword;
	cout << "검색어를 입력하세요 (시도 또는 시군구) ..... [                   ]\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";
	cin >> keyword;
	int chk = 0;
	cout << endl;
	int subTotal[LOCATION_NUMBER];
	for (int i = 0; i < LOCATION_NUMBER; i++)
	{
		subTotal[i] = 0;
	}

	for (int i = 0; i < list.size(); i++)
	{
		if (keyword.compare(list.at(i)->GetSiDo()) == 0)
		{
			for(int j=0; j< LOCATION_NUMBER;j++)
			{
				subTotal[j] += *(list.at(i)->GetAccidentCount() + j);
			}
			chk++;
		}
	}

	if (chk == 0)
	{
		for (int i = 0; i < list.size(); i++)
		{
			if (keyword.compare(list.at(i)->GetSiGunGoo()) == 0)
			{
				for (int j = 0; j < LOCATION_NUMBER; j++)
				{
					subTotal[j] += *(list.at(i)->GetAccidentCount() + j);
				}
			}
		}
	}

	cout << keyword << "의 부분합 : ";
	for (int i = 0; i < LOCATION_NUMBER; i++)
	{
		cout << subTotal[i] << " ";
	}

	cout << endl<< endl;
	
	cout << endl;

	int choose = 0;
	cout << "검색 결과를 파일로 저장하시겠습니까? [ 1.예 / 2.아니오 ]" << endl << endl;
	cout << "선택 : [_]\b\b";
	cin >> choose;
	if (choose == 1)
	{
		string temp;
		temp = keyword + "의 부분합 : ";
		for (int j = 0; j < LOCATION_NUMBER; j++)
		{
			temp += to_string(subTotal[j]);
			if (j != LOCATION_NUMBER - 1)
			{
				temp += ",";
			}
		}
		SaveSubTotalToFile(keyword, temp);
	}
	else if (choose == 2)
	{
		cout << "메뉴로 돌아갑니다..." << endl;
		Sleep(500);
	}
}

void AccidentList::SaveListToFile(string Keyword, vector<int> searchedRow)
{
	cout << endl << "저장할 파일명을 입력해주세요 (영문, 20글자 이내) : ";
	cout << "____________________\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";
	string fileName;
	cin >> fileName;
	string extension = ".csv";
	ofstream myfile;
	myfile.open(fileName+extension);
	for(int j=0; j<searchedRow.size();j++)
	{
		myfile << MakeRowToStr(searchedRow.at(j));
	}
	myfile.close();
}

string AccidentList::MakeRowToStr(int i)
{
	string temp;
	temp = list.at(i)->GetSiDo() + "," + list.at(i)->GetSiGunGoo() + ",";
	
	for (int j = 0; j < LOCATION_NUMBER; j++)
	{
		temp += to_string(*(list.at(i)->GetAccidentCount() + j));
		if (j != LOCATION_NUMBER - 1)
		{
			temp+=",";
		}
	}
	temp += "\n";
	return temp;
}

void AccidentList::SaveSubTotalToFile(string Keyword, string subTotalStr)
{

	cout << endl << "저장할 파일명을 입력해주세요 (영문, 20글자 이내) : ";
	cout << "____________________\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";
	string fileName;
	cin >> fileName;
	string extension = ".csv";
	ofstream myfile;
	myfile.open(fileName + extension);
	myfile << subTotalStr;
	myfile.close();

}

void AccidentList::deleteAll()
{
	for (int i = 0; i< list.size();i++)
	{
		delete list.at(i);
	}
}

 

 

파일 출력부분은 저장할 파일명을 입력받고 확장자와 더해서 해당 파일명으로 검색결과를 출력한다.

string 클래스를 사용하니 쉽게 구현이 가능하였다.


부분합 부분은 어차피 한줄이라 부분합검색 함수에서 한줄을 string으로 만들어 SaveSubTotalToFile 함수의 매개변수로 키워드와 같이 넘기고, 리스트 부분은 가변적이라서 리스트검색 함수 내에서 행 번호를 vector<int> 타입에 저장해 놓고 SaveListToFile 함수를 호출하며 키워드와 벡터를 매개변수로 넘긴다. 그냥 값 복사 형태로 넘기게끔 했고 리스트 파일출력 을 위해 행 한 줄을 string으로 만드는 부분을 MakeRowToStr 라는 이름으로 함수화 했다.

 

 

 

 

AccidentData.h

#pragma once
#include <iostream>
#include <string>
#define COLUMN_NUMBER 13
#define LOCATION_NUMBER 11

using namespace std;

class AccidentData
{
private:
	string siDo;
	string siGunGoo;
	int accidentCount[LOCATION_NUMBER];


public:
	AccidentData(string _siDo, string _siGunGoo, string* _accidentCount);

	string GetSiDo() const;
	string GetSiGunGoo() const;
	int* GetAccidentCount();

	~AccidentData();
};

 

 

 

 

 

AccidentData.cpp

#include "AccidenData.h"
#include <iostream>
#include <string>

#include "AccidenData.h"

AccidentData::AccidentData(string _siDo, string _siGunGoo, string* _accidentCount)
{
	siDo = _siDo;
	siGunGoo = _siGunGoo;
	for (int i = 0; i < LOCATION_NUMBER; i++)
	{
		if (*(_accidentCount + i) == "-")
		{
			accidentCount[i] = 0;
		}else
		{
			accidentCount[i] = stoi(*(_accidentCount + i));
		}		
	}
}

string AccidentData::GetSiDo() const
{
	return siDo;
}

string AccidentData::GetSiGunGoo() const
{
	return siGunGoo;
}

int* AccidentData::GetAccidentCount()
{
	return accidentCount;
}