ここから本文です

C++言語のプログラミングについての質問です。

アバター

ID非公開さん

2020/1/2419:26:35

C++言語のプログラミングについての質問です。

test2019.txt を読み込み、数学の点数をキーデータとして降順に並べ替え、もし数学の点数が同じ場合は、国語の点数が高いほうを上位とするプログラムを作成してほしいです。



test2019.txt
クラス名 名前 英語 数学 国語
1 akiyama 67 89 78
2 kimura 79 86 92
1 tanaka 62 85 79
1 inoue 96 86 91
2 satou 69 74 70
2 nomura 89 85 71
2 mutou 65 58 90
2 harada 78 85 82
1 ueda 93 84 69
1 enomoto 59 88 75
2 okada 62 85 97
1 yamada 98 75 84
2 watanabe 89 71 96
1 chida 87 90 91




よろしくお願いします。

閲覧数:
57
回答数:
2

違反報告

ベストアンサーに選ばれた回答

プロフィール画像

カテゴリマスター

n2q********さん

2020/1/2508:58:35

【プログラム例】

#include <string>
#include <fstream>
struct 成績 {
int クラス名;
std::string 名前;
int 英語;
int 数学;
int 国語;
friend std::istream& operator>>(std::istream& stream, 成績& d)
{
return stream
>> d.クラス名
>> d.名前
>> d.英語
>> d.数学
>> d.国語
;
}
bool operator<(const 成績& d) const
{
const auto キーデータ = 数学 == d.数学 ? &成績::国語 : &成績::数学;
return this->*キーデータ > d.*キーデータ;
}
};
#include <vector>
std::istream& operator>>(std::istream&& stream, std::vector<成績>& t)
{
for (成績 個人成績データ;;) {
if (stream >> 個人成績データ)
t.emplace_back(個人成績データ);
else {
stream.clear();
return stream;
}
}
}
#include <algorithm>
#include <iostream>
#include <iomanip>
int main()
{
std::vector<成績> t;
if (std::ifstream("test2019.txt") >> t) {
std::sort(t.begin(), t.end());
for (const auto& d : t) {
std::cout
<< d.クラス名
<< std::setw(9) << d.名前
<< std::setw(4) << d.英語
<< std::setw(4) << d.数学
<< std::setw(4) << d.国語
<< std::endl;
}
}
}


【解説】


〔test2019.txt を読み込み〕について

成績構造体を用意し、std::istream (つまり、ファイルのことです)からの読み込みを実施する >> 演算子を friend として定義しました。構造体なので friend にしなくてもよさそうなものですが、このようにメンバではない関数をメンバのように構造体の中に記述できるのが friend の良さだと考えます。


〔数学の点数をキーデータとして降順に並べ替え、もし数学の点数が同じ場合は、国語の点数が高いほうを上位とする〕について

< 演算子をオーバーロードしました。

数学 == d.数学 ということで両者の数学の点数が等しい場合、&成績::国語を、そうでない場合は &成績::数学をキーデータとしています。

その上で、this->*キーデータが d.*キーデータよりも大きいことを表すブール値を返すことで「降順に並べ替え」を実現しています。



《参考》

以前類似するご質問をお見掛けしましたがその際のご質問者のコードは C 言語の処理手法によって書かれていました。今回お示ししましたものは C++ による典型的な処理手法になります。C++ は C 言語の全体を含んだ言語ですので勿論 C 言語の書き方であっても C++ としてそのまま動きます。(ごく一部、C++ 用に若干の改変を要する場合もあったりしますが。)

でも、やはり C++ の課題ということからしますと、これは C++ としての書き方をした方が良いだろうと考えた次第です。


「キーデータ」の箇所が若干難しい書き方になっているかもしれませんが、でもこれは「キーデーター」という概念が課題文で示されている格好となっているので、それに対応するものと考えます。

if (数学 == d.数学)
return 国語 > d.国語;
else
return 数学 > d.数学;

とか

return 数学 == d.数学
? 国語 > d.国語
: return 数学 > d.数学
;

とか、他にも書き方は考えられますが、しかしながらいずれも「キーデータ」という概念に対応するものが全く見えてこない書き方であると思います。

そこで今回はメンバ変数へのポインタというものを登場させて、これを「キーデータ」であるという風に見るものとしました。


プログラムを作る上で大切なことは、課題(実務では要件、要求仕様)との対応関係だと思っています。課題がどのように処理されているのかが、課題の文面と対応付けて見ることのできるプログラムにすることが大切という意味です。この点を考慮しないと、課題とプログラムとが全く対応が取れない、うごかしてみると確かにそう動くが、何がどうなってそう動くのか分からない…といった問題が生じてきます。こうなると、まず勉強になりません。知識や技術が習得できないのです。そして更に、間違いがあった時に直すのが大変です。実務ではそこに余分な費用が掛かってしまいます。間違いではないにしろ動きを改善したい場合などにも、この点は引っ掛かってきます。


以上、個人的な考え方を申し上げましたが、何か参考になるところがありましたら嬉しく思います。

返信を取り消しますが
よろしいですか?

  • 取り消す
  • キャンセル

ベストアンサー以外の回答

1〜1件/1件中

leh********さん

2020/1/2502:05:48

#include <iostream>
#include <fstream>
#include <sstream>
#include <iterator>
#include <algorithm>
#include <string>
#include <vector>

using std::ifstream;
using std::ostream_iterator;
using std::istringstream;
using std::string;
using std::vector;
using std::next;
using std::copy;
using std::sort;
using std::cout;
using std::endl;

bool ReadSsv(const char *ps, vector<vector<string>> &svv);
int Cmp(const vector<string> &lhs, const vector<string> &rhs);

int main(void)
{
  vector<vector<string>> test;
  if (ReadSsv("test2019.txt", test)) {
    sort(next(test.begin()), test.end(), Cmp);
    for (const auto &ts : test) {
      copy(ts.begin(), ts.end(), ostream_iterator<string>(cout, " "));
      cout << endl;
    }
  }
  return 0;
}

bool ReadSsv(const char *ps, vector<vector<string>> &svv)
{
  if (ps) {
    ifstream ifs(ps);
    if (ifs) {
      string line;
      for (int i = 0; getline(ifs, line); ++i) {
        //if (i == 0) continue;
        istringstream iss(line);
        string item;
        vector<string> sv;
        while (getline(iss, item, ' ')) {
          sv.push_back(item);
        }
        svv.push_back(sv);
      }
      return true;
    }
  }
  return false;
}

enum { MATH = 3, JPLANG = 4 };

int CmpMath(const vector<string> &lhs, const vector<string> &rhs) {
  istringstream lss(lhs[MATH]), rss(rhs[MATH]);
  int lval, rval;
  lss >> lval, rss >> rval;
  return lval - rval;
}

int CmpJplang(const vector<string> &lhs, const vector<string> &rhs) {
  istringstream lss(lhs[JPLANG]), rss(rhs[JPLANG]);
  int lval, rval;
  lss >> lval, rss >> rval;
  return lval - rval;
}

int Cmp(const vector<string> &lhs, const vector<string> &rhs) {
  int (*func[])(const vector<string> &lhs, const vector<string> &rhs) = { &CmpMath, &CmpJplang };
  for (auto &&fnc : func) {
    int ret = fnc(lhs, rhs);
    if (ret) return ret > 0;
  }
  return 0;
}

みんなで作る知恵袋 悩みや疑問、なんでも気軽にきいちゃおう!

Q&Aをキーワードで検索:

Yahoo! JAPANは、回答に記載された内容の信ぴょう性、正確性を保証しておりません。
お客様自身の責任と判断で、ご利用ください。
本文はここまでです このページの先頭へ

「追加する」ボタンを押してください。

閉じる

※知恵コレクションに追加された質問は選択されたID/ニックネームのMy知恵袋で確認できます。

不適切な投稿でないことを報告しました。

閉じる