集計したデータの並べ替えを実現するには?
解決済
回答 5
投稿
- 評価
- クリップ 0
- VIEW 3,099
JAVA初心者です。
月別の売上金額の大きい3商品を出力するプログラムを
作成しています。
以前こちらで問題点を解決いただき、完成には近づいているのですが
再び自身では解決できないことがあり投稿させていただきました。
【完成例】
商品名,数量 ,売上金額 ,備考
201601月売上高BEST3
バナナ,10,100,
玉ねぎ,8,80,
トマト,6,60,
201602月売上高BEST3
バナナ,15,150,
玉ねぎ,14,140,
白菜,10,110,
商品マスタ未存在,,,
,,,日付に誤りがあります
【仕様内容】
売上明細をもとに商品マスタより商品名と単価を取得します。
売上金額の大きい商品の順に並び替えをして上位3つを出力します
(sort機能は使用しない)。
商品を出力する前に「yyyymm月売上高BEST3」を出力します。
【解決したいこと】
売上データが蓄積されたHashMapから合計金額を抽出し新たな配列に格納して大きい順に
並び替えをしたいのですが、sortAmountメソッドのところで「演算子 < は引数の型
lesson.Profit, lesson.Profit で未定義です」とEclipseに指摘されてしまいます。
この場合はどうすればよろしいのでしょうか?
どうぞよろしくお願いいたします。
package lesson;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map.Entry;
public class MonthlySalesBest3 {
public static BufferedWriter bwA = null ; //月額売上表出力ファイル
public static void main(String[] args) {
BufferedReader brA = null ; //売上明細入力ファイル
String stA = ""; //inAファイルデータを格納
String[] itemA = null ; //inAファイルデータを配列に格納
HashMap<String, Profit> totalHolder = null ; //商品別一式の売上データを格納
String date = ""; //売上明細ファイルの購入月をセット
boolean isFirst = false; //0番目の購入日をセットする為の変数
final String noItem = "商品マスタ未存在";
final String noDate = "日付に誤りがあります";
boolean emptyflgA = false; //売上明細入力ファイル空判定フラグ
try{
fileError:{
try{
brA = new BufferedReader(new InputStreamReader(new FileInputStream("C:/Users/temp/Desktop/inA.csv"),"JISAutoDetect"));
}catch(FileNotFoundException e){
System.err.println("inA.csvファイルが見つかりません。");
}
try{
bwA = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("C:/Users/temp/Desktop/outA.csv"),"SJIS"));
}catch(FileNotFoundException e){
System.err.println("outA.csvファイルが見つかりません。");
}
/**
* 商品マスタ一覧を入力するメソッド
*/
ProductMasterList.productList();
bwA.write("商品名" + "," + "数量" + " ," + "売上金額" + " ," + "備考"); //ヘッダー行を出力
bwA.newLine();
try{
while((stA = brA.readLine()) != null){
if(stA.equals("")){
System.err.println("データに不備があります。");
break fileError;
}
emptyflgA = true;
itemA = stA.split(",");
ProductMasterList.mpDM = ProductMasterList.alDM.get(itemA[1]);
if(isFirst == false){ //date変数に売上月がセットされているか確認
date = itemA[0].substring(0, 6);
isFirst = true;
}
String soldDate = (itemA[0].substring(0, 6));
int sold= soldDate.compareTo(date); //月変更の比較
if(sold > 0){
bwA.write(date.substring(0, 6) + "月売上高BEST3"); //月売上高BEST3を出力
bwA.newLine();
Profit[] arr = null;
int i = 0;
for(Entry<String, Profit> entry : totalHolder.entrySet()) {
//System.out.println(entry.getKey() + " ," + entry.getValue().count + " ," + entry.getValue().salesAmount);
arr = totalHolder.values().toArray(new Profit[i]);
//System.out.println(arr[i]);
i += 1;
}
/**
* 売上金額を大きい順に並べ替えるメソッド
*/
sortAmount(arr);
date = itemA[0]; //売上日を再セット
}
if(ProductMasterList.alDM.containsKey(itemA[1])){
if(checkDate(itemA[0])){ //日付の妥当性を確認
if(totalHolder == null){
totalHolder = new HashMap<String, Profit>();
}
String itemName = (String) ProductMasterList.mpDM.get("name");
if(!totalHolder.containsKey(itemName)) { //totalHolderに名前が登録されてなければ新しく登録。
totalHolder.put(itemName, new Profit());
totalHolder.get(itemName).itemName = itemName; // あとで値出力の時に使う
}
// 売上数量と売上金額を加算。
totalHolder.get(itemName).count += Integer.parseInt(itemA[2]);
totalHolder.get(itemName).salesAmount += Integer.parseInt(itemA[2]) * Integer.parseInt(ProductMasterList.itemM[2]);
} else{
String e = ""; //備考
e = noDate; //備考=日付に誤りがあります
}
}else{
Object b = noItem; //商品名=商品マスタ未存在
}
}//while
if(emptyflgA == false){
System.err.println("inA.csvファイルが空です。");
break fileError;
}
}catch(IOException e){
e.printStackTrace();
}
}//fileError
}catch(IOException e){
System.err.println("何らかのエラーが発生しました。");
}
finally{
try {
brA.close();
ProductMasterList.brM.close();
bwA.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}//main
/**
* 日付の妥当性をチェック
* カレンダーに存在するかどうかを返す。
* 存在する日付の場合true
*/
public static boolean checkDate(String strDate) {
if (strDate == null || strDate.length() != 8) {
throw new IllegalArgumentException(
"引数の文字列["+ strDate +"]" +
"は不正です。");
}
DateFormat format = new SimpleDateFormat("yyyyMMdd");
format.setLenient(false);
try {
format.parse(strDate);
return true;
} catch (Exception e) {
return false;
}
}
/**
* 売上金額を大きい順に並べ替えるメソッド
*/
public static Profit[] sortAmount(Profit[] arr){
for(int i=0; i<arr.length-1; i++){ //売上金額を昇順に並べ替え
for(int j=i+1; j < arr.length; j++){
if(arr[i] < arr[j]){
Profit temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
}
}
return arr;
}
/**
* 売上金額の上位3位を出力するメソッド
*/
public static void outputBest3(){
for(int i=0; i < 3; i++){
String name = totalHolder.get(itemName).itemName[i]; //商品名
int cnt = totalHolder.get(itemName).count[i]; //数量
int amt = totalHolder.get(itemName).salesAmount[i]; //合計額
bwA.write(name + "," + cnt + "," + amt + ",");
bwA.newLine();
}
}
}
package lesson;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
public class ProductMasterList {
public static BufferedReader brM = null ; //商品マスタ入力ファイル
public static String stM = ""; //inMファイルデータを格納
public static String[] itemM = null ; //inMファイルデータを配列に格納
public static HashMap<String, Object> mpDM = null; //商品マスタデータを格納
public static HashMap<String,HashMap<String,Object>> alDM = new HashMap<String,HashMap<String,Object>>() ; //商品マスタの入力データを格納
public static boolean emptyflgM = false; //商品マスタファイル空判定フラグ
public static HashMap<String, HashMap<String, Object>> productList( ){
try{
try {
brM = new BufferedReader(new InputStreamReader(new FileInputStream("C:/Users/temp/Desktop/inM.csv"),"JISAutoDetect"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}catch(FileNotFoundException e){
System.err.println("inM.csvファイルが見つかりません。");
}
//inMファイルデータを読み込み
try {
while((stM = brM.readLine()) != null){
if(stM.equals("")){
System.err.println("データに不備があります。");
}
emptyflgM = true;
itemM = stM.split(",");
mpDM = new HashMap<String,Object>();
mpDM.put("code", itemM[0]); //商品コード
mpDM.put("name", itemM[1]); //商品名
mpDM.put("price", itemM[2]); //単価
alDM.put(itemM[0],mpDM); //商品コードをキー、mpDMを値にして格納
}
} catch (IOException e) {
e.printStackTrace();
}//while
if(emptyflgM == false){
System.err.println("inMファイルが空です。");
//break fileError;
}
return alDM;
}
}
package lesson;
class Profit {
/** 商品名 */
public String itemName = null;
/** 売上数量 */
public int count = 0;
/** 売上金額 */
public int salesAmount = 0;
}
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+1
class MonthlySalesBest3内、メソッドsortAmountでのif文「if(arr[i] < arr[j]){」←arr[i]はProfitクラスのインスタンスです。
クラスのインスタンスどうしなのでこれでは比較ができません。
class Profitで比較するのに使うのはなんでしたっけ?
売上金額ではないですか?
class Profit {
/** 商品名 */
public String itemName = null;
/** 売上数量 */
public int count = 0;
/** 売上金額 */
public int salesAmount = 0; // <- これで比較するんじゃね?
}
ではsalesAmountを取ってくるにはどうすればいいでしょう?
インスタンスのpublicなメンバ変数にアクセスするには「[インスタンス名].[メンバ変数名]」です。
arr[i]のsalesAmountにアクセスするなら「arr[i].salesAmount」としなければ。
これをほかの売上金額と比較するんでしょ?
「if ( 1 < 2 )」の1、2に該当するところに「arr[i].salesAmount」などなどを入れるのです。
ついでに、
/**
* 売上金額の上位3位を出力するメソッド
*/
public static void outputBest3(){
for(int i=0; i < 3; i++){
String name = totalHolder.get(itemName).itemName[i]; //商品名
int cnt = totalHolder.get(itemName).count[i]; //数量
int amt = totalHolder.get(itemName).salesAmount[i]; //合計額
bwA.write(name + "," + cnt + "," + amt + ",");
bwA.newLine();
}
}
↑これは何をしているのでしょう?
「totalHolder」はstatic なHashMap<String, Profit>なはずです。
totalHolder.get(itemName).salesAmount[i]; //合計額
↑こんなんしてもコンパイルエラーになりますよ?
■以下追加:
for(Entry<String, Profit> entry : totalHolder.entrySet()) {
//System.out.println(entry.getKey() + " ," + entry.getValue().count + " ," + entry.getValue().salesAmount);
arr = totalHolder.values().toArray(new Profit[i]);
//System.out.println(arr[i]);
i += 1;
}
まずここ。
無意味なループです。
ここでやりたいことは
・「Profit[] arr = null;」で宣言したProfitインスタンスの配列にHashMap<String, Profit>の中身を詰め込む。
ことですね。
arr = totalHolder.values().toArray(new Profit[]);
この1行で完了します。
また、
/**
* 売上金額を大きい順に並べ替えるメソッド
*/
sortAmount(arr);
ここではメソッドにProfit配列を渡して処理してもらってますね?
これと同じように、出力するメソッドも
/**
* 売上金額の上位3位を出力するメソッド
*/
public static void outputBest3(Profit[] arr){
のように定義してやって、このメソッドにソートが終わった配列を渡してあげれば完了ではありませんか?
// outputBest3の実行
outputBest3(arr);
まとめ:
こんな書き方になるはずです。
if(sold > 0){
// 1.新しい月の売上が出てきたので、今までの分を出力
// 2.処理対象の月のヘッダを出力する
bwA.write(date.substring(0, 6) + "月売上高BEST3");
bwA.newLine();
// 3.Profitインスタンスの配列にHashMap<String, Profit>の中身を詰め込む
arr = totalHolder.values().toArray(new Profit[]);
// 4.上で取得したProfit配列を売上金額が大きい順に並べ替える
sortAmount(arr);
// 5.売上金額の上位3位を出力する
outputBest3(arr);
date = itemA[0]; //売上日を再セット
}
「何を」「どうする」というのがしっかり切り分けられないとプログラムになりません。(この場合の主語は「プログラムが」)
このことが明確になってないとプログラムはおかしくなります。
たとえば質問のソースで
// 商品マスタ一覧を入力するメソッド
ProductMasterList.productList();
こんなのがありましたが、この1行でやってることはなんですか?
「何を」「どうする」にあてはめると、「商品マスタ一覧を」「取得する」ではありませんか?
入力じゃないですよね?
ささいなことかもしれませんが、コメントに書いていることと実際の処理内容が食い違っていれば勘違いや混乱のもとになります。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+1
前の方の回答の通り、数値の比較に使う<>をオブジェクトに使うことは出来ません(数値のラッパークラスオブジェクトを除く)。
簡単に並べ替えを実現するには、Comparator<Profit>実装クラスを作ってArrays.sortに配列ともども渡すことですね。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
0
自作クラスProfitに対しては比較演算子は使えません。
Profit#salesAmountに対しての比較に変更する必要があります。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
0
Profitのインスタンスを < で比較しているからでしょう。
arr[i].salesAmount < arr[j].salesAmount ではないですか?
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
0
エラーの原因)
Profitクラスのオブジェクトどうしを、"<"で比較しようとしているのですから、エラーになります。
"<"は、数値比較の演算子ですから。
sortAmountのコードを以下のように修正すれば、問題は解決すると思います(動作確認はしていません)
public static Profit[] sortAmount(Profit[] arr){
for(int i=0; i<arr.length-1; i++){ //売上金額を昇順に並べ替え
for(int j=i+1; j < arr.length; j++){
// if(arr[i] < arr[j]){ //この行でエラーが出ている
if(arr[i].salesAmount < arr[j].salesAmount){ //オブジェクトどうしを比較するのではなく、売上金額(salesAmount)どうしを比較するように修正。
Profit temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
}
}
return arr;
}
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.37%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2016/03/31 12:12
class Profitの売上金額を比較しないといけないことは分かっていたのですが、
メンバ変数にアクセスする方法が分かりませんでした、教えていただきありがとう
ございました。
それから、outputBest3メソッドについて、改めて考えると「totalHolder」はインスタンスではないので、コンパイルエラーになるのは当然だと分かりました。
では、どうすれば並べ替えをしたインスタンスの情報を取り出すことができるのか教えていただけないでしょうか?
よろしくお願いいたします。
2016/03/31 13:23 編集
2016/04/01 18:27
今の私には、ご説明いただいた内容を明確に理解することは難しいですが、
教えていただいたことを整理しながら理解していけるよう努めていきます。
何度もご質問して申し訳ありませんが、
>arr = totalHolder.values().toArray(new Profit[]);
上記の箇所の(new Profit[])に「変数はディメンション式または配列イニシャライザーのどちらかを提供しなければなりません」とエラーが表示されるのですが、どのように対処すれば良いのか、またこのエラー内容はどのような意味なのか教えていただけないでしょうか、よろしくお願いいたします。
2016/04/01 18:29
2016/04/01 19:19
的確なご指摘をいただいたおかげで無事すべての問題点が解決しプログラムが完成しました。
本当にありがとうございました。