質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

2回答

2159閲覧

CSVファイルのデータ集計

Welchs

総合スコア7

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

1クリップ

投稿2018/01/15 10:56

###前提・実現したいこと
javaでCSVファイルのデータを読み込み、カテゴリ別に価格の総合を計算し、その結果を画面に出力し、CSVファイルで保存したいです。

CSVファイルの読み込み内容
カテゴリー,商品,価格
食品,水,90
日用品,タオル,500
食品,弁当,500
日用品,ブラシ,600
家電品,冷蔵庫,60000
食品,バナナ,200
家電品,アイロン,7000
日用品,シャンプー,700

出力画面表示結果
カテゴリー,総合
食品:790
日用品:1800
家電品:67000

###発生している問題・エラーメッセージ

エラーメッセージ

###該当のソースコード

ここにご自身が実行したソースコードを書いてください package java_practice; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.StringTokenizer; public class CSV { public static void main(String args[]) { try { //ファイルを読み込む FileReader fr = new FileReader("c:\Users\data.csv"); BufferedReader br = new BufferedReader(fr); //読み込んだファイルを1行ずつ処理する String line; StringTokenizer token; while ((line = br.readLine()) != null) { //区切り文字","で分割する token = new StringTokenizer(line, ","); //分割した文字を画面出力する while (token.hasMoreTokens()) { System.out.println(token.nextToken()); } System.out.println("**********"); } //終了処理 br.close(); } catch (IOException ex) { //例外発生時処理 ex.printStackTrace(); } } } ###試したこと 課題に対してアプローチしたことを記載してください CSVファイルのデータを読み込むところまでできました。それ以下のコードの表し方に苦戦しています。 ###補足情報(言語/FW/ツール等のバージョンなど) より詳細な情報

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

#hashmapにぶち込めばいいんじゃないかな?

java

1HashMap<String,Integer> map=new HashMap<>(); 2while (token.hasMoreTokens()) { 3 String cate=token.nextToken(); token.nextToken(); 4 Integer val=Integer.valueOf(token.nextToken()); 5 map.merge(cate,val,Integer::sum);//使えないなら普通に足すこと 6}

問題点
想定している出力順と違う可能性がある
LinkedHashMap使おう
#気になる点
例外発生時にbrが閉じられない

  • finally使う
  • try with resources使う

StringTokenizerはレガシークラス(新規での使用は勧められない)
String#split(String)使う
java.util.regix使う

#上2つを直したやつ

java

1try(BufferedReader br=new BufferedReader(new FileReader("c:\Users\data.csv"))){ 2 String[] header=br.readLine().split(",");//一行目見出し 3 String line; 4 while((line=br.readLine())!=null){ 5 HashMap<String,Integer> map=new HashMap<>(); 6 String[] token=line.split(","); 7 String cate=token[0]; 8 Integer val=Integer.valueOf(token[2]); 9 map.merge(cate,val,Integer::sum); 10 } 11 System.out.println(header[0]+",総合"); 12 map.forEach((k,v)->System.out.println(k+":"+v)); 13}catch(IOException ex){ 14 ex.printStackTrace(); 15}

問題点
想定していた出力順を得られない→解決策は同じ

#一言
問題点は明確でない仕様のせいであるかないかわからなくなってます。
Java8な感じでも書こうと思ったけどヘッダー行のせいでメンドーなことに。

投稿2018/01/15 12:34

編集2018/01/15 17:20
tignear

総合スコア260

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

swordone

2018/01/15 16:44

StringTokenizerはレガシークラスで、新規に使う際はString#splitを使うようドキュメントで指示されています。
tignear

2018/01/15 17:32

回答を編集しました。 ご指摘ありがとうございます。
guest

0

ベストアンサー

集約結果を出力するcsvファイル名が質問文では指定されていなかったので、grouped.csvという名前にしておきました。
集約結果を表示とwriteメソッドはStream APIを使った形に改良できそうな気がしますが・・・

Java

1import java.io.BufferedReader; 2import java.io.BufferedWriter; 3import java.io.File; 4import java.io.IOException; 5import java.nio.charset.Charset; 6import java.nio.file.Files; 7import java.nio.file.Paths; 8import java.util.Map; 9import java.util.Map.Entry; 10import java.util.stream.Collectors; 11 12public class Q109103 { 13 14 public static void main(String[] args) { 15 File data_file = new File("c:\Users\data.csv"); 16 File grouped_file = new File("c:\Users\grouped.csv"); 17 try { 18 Map<String, Long> grouped = readAndgrouped(data_file); 19 // 集約結果を表示 20 grouped.forEach((k, v) -> System.out.println(k + ":" + String.valueOf(v))); 21 // ファイルに出力 22 write(grouped_file, grouped); 23 } catch (IOException ex) { 24 ex.printStackTrace(); 25 } 26 } 27 28 public static Map<String, Long> readAndgrouped(File data_file) throws IOException { 29 try (BufferedReader br = Files.newBufferedReader(Paths.get(data_file.toURI()))) { 30 Map<String, Long> grouped = br.lines().skip(1).map((String line) -> { 31 String[] arr = line.split(","); 32 return new CsvData(arr[0], arr[1], Long.parseLong(arr[2])); 33 }).collect(Collectors.groupingBy(x -> x.category, Collectors.summingLong(x -> x.price))); 34 return grouped; 35 } 36 } 37 38 public static void write(File grouped_file, Map<String, Long> grouped) throws IOException { 39 Charset encoding = Charset.forName("Windows-31j"); 40 try (BufferedWriter bw = Files.newBufferedWriter(Paths.get(grouped_file.toURI()), encoding)) { 41 // ヘッダー行 42 bw.write("カテゴリー,総合"); 43 bw.newLine(); 44 // データ行 45 for (Entry<String, Long> entry : grouped.entrySet()) { 46 bw.write(entry.getKey()); 47 bw.write(":"); 48 bw.write(String.valueOf(entry.getValue())); 49 bw.newLine(); 50 } 51 } 52 } 53} 54 55class CsvData { 56 final String category; 57 final String subitem; 58 final Long price; 59 60 public CsvData(String category, String subitem, Long price) { 61 this.category = category; 62 this.subitem = subitem; 63 this.price = price; 64 } 65 66 @Override 67 public String toString() { 68 String[] array = { this.category, this.subitem, String.valueOf(this.price) }; 69 return String.join(" ", array); 70 } 71}

投稿2018/01/15 18:14

編集2018/01/15 18:25
umyu

総合スコア5846

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tignear

2018/01/16 00:31

String lsep=System.lineSeparator(); grouped.map((k,v)->k+":"+v+lsep).forEach(bw::write); こうですか?(なんかあまり良くなさげ)
Welchs

2018/01/16 05:19

回答ありがとうございます。 Map<String, Long> grouped = readAndgrouped(data_file); と Map<String, Long> grouped = br.lines().skip(1).map((String line) -> { String[] arr = line.split(","); return new CsvData(arr[0], arr[1], Long.parseLong(arr[2])); }).collect(Collectors.groupingBy(x -> x.category, Collectors.summingLong(x -> x.price))); の行で実行がうまくいかなかったです。 変数のスコープを設定すればよいでしょうか?
tignear

2018/01/16 06:15

例外の型とスタックトレースを書いてください。 java.lang.NumberFormatExceptionでcsvがここからコピーしたままのものなら最後に空白が入ってるのが悪い。 余計な空白(これも定義が難しいなぁ)に対応したいなら(ここでは三番目のキーの数字以外のものを余計なものとして処理する) Long.parseLong(arr[2].replaceAll("\D","")));にするとか。
umyu

2018/01/16 13:49

tsukkaさんへ コードのヘルプありがとうございました。 Welchsさんへ 1,あと可能性として有り得そうなのが入力ファイルのファイルエンコード形式が違うとかそーいう問題がありますが。エラーが発生した時のメッセージを追加してください。 2,あくまでもこれはこういう書き方ができますよというサンプルソースコードなので、コードの意味を理解していないままそのまま取り込むのは大変危険な行為です。
swordone

2018/01/17 03:19

集約するだけならわざわざCsvDataなんてクラスを作らなくてもいいような Map<String, Long> grouped = br.lines().skip(1).map(line -> line.split(",")) .collect(Collectors.groupingBy(x -> x[0], Collectors.summingLong(y -> Long.parseLong(y[2])))); 書いてて気付いた。summingLongのラムダの引数にxを使うと重複する。
Welchs

2018/01/17 06:48

皆様へ 回答ありがとうございます。 umyuさんへ 1.こういうエラーメッセージが出ています。 デバックでは、値を返すメソッドが存在しないとででいます。 Exception in thread "main" java.io.UncheckedIOException: java.nio.charset.MalformedInputException: Input length = 1 at java.io.BufferedReader$1.hasNext(BufferedReader.java:574) at java.util.Iterator.forEachRemaining(Iterator.java:115) at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801) at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) at scvfiledatacounting.File01.readAnddata2(File01.java:37) at scvfiledatacounting.File01.main(File01.java:22) Caused by: java.nio.charset.MalformedInputException: Input length = 1 at java.nio.charset.CoderResult.throwException(CoderResult.java:281) at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:339) at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178) at java.io.InputStreamReader.read(InputStreamReader.java:184) at java.io.BufferedReader.fill(BufferedReader.java:161) at java.io.BufferedReader.readLine(BufferedReader.java:324) at java.io.BufferedReader.readLine(BufferedReader.java:389) at java.io.BufferedReader$1.hasNext(BufferedReader.java:571) ... 9 more 2.ご指摘ありがとうございます。javaの勉強始めてまだ間もないですが、ソースコードの理解に、日々奮闘中です。
tignear

2018/01/17 07:08 編集

エンコードがあってないって怒られてます。 csvファイルのエンコードとCharset.forName("Windows-31j");のエンコードを合わせてください。 もしUTF-8ならBOMを使っているのか確認すること。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問