c++, 조건부 sort하기

minyoung347의 이미지

안녕하세요,

대용량 문서를 sort하려고 하는데
조건을 줘서 여러번 분류해야 하는 상황이 생겼습니다.
설명을 드리기 위해서 코드를 간단하게 만들었습니다.

test.csv 파일에는 6명의 성적이 있습니다.
각각의 학생은 class_A 또는 class_B에서 속해 있습니다.

제가 하고 싶은 것은 6명의 학생을 class별로 먼저 분류하고
그 다음에 성적별로 분류하는 것입니다.

아래의 코드와 같이 하면 높은 성적을 받은 학생이 위로 올라오게 됩니다.

그런데 문제는 class_A는 높은 점수을 받은 학생이 잘하는 것이고
class_B는 낮은 점수를 받은 학생이 잘하는 것입니다.

잘하는 학생을 위로 오게 하려면 어떻게 하는지 궁금합니다.

요약하자면, class별로 다른 기준으로 sort하는 방법을 알고싶습니다.
(class_A는 내림차순, class_B는 오름차순)
(code의 Compare_By_string함수에서 string1을 기준으로 class를 분류하고 string2를 기준으로 성적을 분류합니다)

방법을 알려주시면 감사하겠습니다.

(필요없는 헤더파일이 있을 수 있습니다..)

-------test.csv---------
class_A,90
class_B,10
class_A,70
class_B,30
class_A,80
class_B,20
------------------------

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <sys/stat.h>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iomanip>
#include <vector>
#include <algorithm>
#include <iterator>
#include <unistd.h>
using namespace std;
 
class line_class
{
public:
line_class(const string& init_string1, const string& init_string2);
 
friend int Compare_By_string(const line_class& lhs, const line_class& rhs);
friend ostream& operator<<(ostream& os, const line_class& obj)
{
	os<<obj.string1<<','<<obj.string2;
	return os;
}
private:
string string1, string2;
};
 
line_class::line_class(const string& init_string1, const string& init_string2)
:string1(init_string1), string2(init_string2){}
 
 
int Compare_By_string(const line_class& lhs, const line_class& rhs)
{
	if(lhs.string1==rhs.string1)
	{
		return (lhs.string2>rhs.string2);
	}
	else if(lhs.string1!=rhs.string1)
	{
		return (lhs.string1<rhs.string1);
	}
}
 
int main()
{
	ostringstream stream;
	string cc;
	const char* ccc;
	stream.str("");
	stream<<"./test.csv";
	cc=stream.str();
	ccc=cc.c_str();
	ifstream file(ccc);
 
	vector<line_class> vector_line;
 
	string string1, string2;
 
	while(getline(file,string1,',')
	&&getline(file,string2,'\n'))
	{
		vector_line.push_back(line_class(string1, string2));
	}
	file.close();
 
	sort(vector_line.begin(), vector_line.end(),Compare_By_string);
 
	stream.str("");
	stream<<"./result.csv";
	cc=stream.str();
	ccc=cc.c_str();
	ofstream fout(ccc,ios::app);
	std::ostream_iterator<line_class> output_iterator(fout,"\n");
	std::copy(vector_line.begin(),vector_line.end(),output_iterator);
	fout.close();
 
return 0;
}
 의 이미지

클래스 종류가 얼마 안된다면 이렇게 하드코딩해버릴 수도 있죠.
얼마나 유연하게 만들어야 하느냐에 따라 달라진다고 볼 수 있겠습니다.

#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
 
class record{
private:
    string _class;
    int _score;
 
    bool read_class(istream &in){
        string str;
        if(!getline(in, str, ','))
            return false;
        _class = str.substr(6, string::npos);
        return true;
    }
    bool read_score(istream &in){
        string str;
        if(!getline(in, str, '\n'))
            return false;
        _score = atoi(str.c_str());
        return true;
    }
public:
    bool operator<(const record &rhs) const{
        return _class!=rhs._class?_class>rhs._class:_class=="A"?_score<rhs._score:_score>rhs._score;
    }
    bool operator>(const record &rhs) const{
        return rhs < *this;
    }
    istream &read_from(istream &in){
        return (read_class(in) && read_score(in)), in;
    }
    ostream &write_to(ostream &out) const{
        return (out << "class_" << _class << "," << _score << endl);
    }
};
 
istream &operator>>(istream &in, record &r){
    return r.read_from(in);
}
ostream &operator<<(ostream &out, const record &r){
    return r.write_to(out);
}
 
int main(void)
{
    vector<record> records;
 
    {
        ifstream in("./test.csv");
        record r;
        while(in >> r)
        {
            records.push_back(r);
        }
        in.close();
    }
 
    sort(records.begin(), records.end(), greater<record>());
 
    {
        ofstream out("./result.csv",ios::app);
        ostream_iterator<record> out_iter(out);
        copy(records.begin(), records.end(), out_iter);
        out.close();
    }
    return 0;
}
minyoung347의 이미지

덕분에 코드를 간결하게 만들었습니다. 너무 감사합니다!

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.