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

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

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

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

Q&A

解決済

6回答

13683閲覧

年月のリスト化

sobue

総合スコア329

Java

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

0グッド

1クリップ

投稿2016/06/24 09:30

編集2016/06/24 13:56

いつもおせわになっております。
動的に取得できる年月があって
例2015/01~2016/01とあって
2015/01
2015/02
2015/03
.
.
.
2016/01と
出力したいのですが
カレンダークラスを使用してListを使う方法はわかりますが
どうしても処理が難読化してしまうためスマートな方法はありますでしょうか?

java

1import java.util.ArrayList; 2import java.util.Calendar; 3 4public class Test3 { 5 6 public static void main(String[] args) { 7 // TODO 自動生成されたメソッド・スタブ 8 9 String fromym = "201501"; 10 String toym = "201601"; 11 ArrayList<String> yms = new ArrayList<String>(10); 12 Calendar calendar = Calendar.getInstance(); 13 calendar.set(Integer.valueOf(fromym.substring(0, 4)), Integer.valueOf(fromym.substring(4)) - 1, 1); 14 15 // 最初の年月の確認 16 System.out.println(String.valueOf(calendar.get(Calendar.YEAR)) 17 + String.format("%02d", (calendar.get(Calendar.MONTH) + 1))); 18 19 while (!toym.equals(String.valueOf(calendar.get(Calendar.YEAR)) 20 + String.format("%02d", (calendar.get(Calendar.MONTH) + 1)))) { 21 // 一月増やす 22 calendar.add(Calendar.MONTH, 1); 23 yms.add(String.valueOf(calendar.get(Calendar.YEAR)) 24 + String.format("%02d", (calendar.get(Calendar.MONTH) + 1))); 25 } 26 // 出力して確認 27 for (String ym : yms) { 28 System.out.println(ym); 29 } 30 } 31 32} 33

このようになり、かなり分かりづらくなってしまうのでもう少しわかりやすくしたいのです。

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

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

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

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

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

yona

2016/06/24 10:24

スマートかどうかは比較しないと判断できません。あなたの書いたコードを追記してください。
Zuishin

2016/06/24 12:11

複雑になりますか? どの程度をもって複雑と思われてます? 与えられた範囲の最初の 1 日を取得して、それを 1 月ずつ増やせばいいだけのように思いますが、どのような形(文字列なのか Date なのか)で入力があってどのような形で出力するのでしょう?
guest

回答6

0

ベストアンサー

簡潔さにこだわるならintでなんとかするのが良さそうな気もしますが、いろいろやり方はあるからなおさらどういう風に決めるのかでけっこう悩みそうですね。
その方法での回答はきりがないと思うのでやめておきます。

Java8以降でしか使えませんが、やはりDateTimeAPIとStreamで書くのが簡潔だと思います。
後出し気味で申し訳ないですが、同様の回答が無さそうなので書いておきます。

lang

1// import java.time.YearMonth; 2// import java.time.format.DateTimeFormatter; 3// import java.util.List; 4// import java.util.stream.*; 5 6YearMonth ym = YearMonth.of(2015, 1); 7DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM"); 8List<String> monthList = IntStream.range(0, 13) 9 .mapToObj(x -> ym.plusMonths(x).format(dtf)) 10 .collect(Collectors.toList()); 11// => [2015/01, 2015/02, 2015/03, 2015/04, 2015/05, 2015/06, 2015/07, 2015/08, 2015/09, 2015/10, 2015/11, 2015/12, 2016/01]

IntStream.rangeで生成した数列は加算する月数で、それぞれの数値を基準となる年月に足したものに変換しつつフォーマットしてできあがりです。


(追記)

無限ストリームを使った方がよりスッキリする気がします。
(この辺、久しぶりに使ったのですぐに思いつきませんでした。)

lang

1// import java.time.YearMonth; 2// import java.time.format.DateTimeFormatter; 3// import java.util.List; 4// import java.util.stream.*; 5 6DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM"); 7List<String> monthList = Stream.iterate(YearMonth.of(2015, 1), x -> x.plusMonths(1)) 8 .limit(13) 9 .map(dtf::format) 10 .collect(Collectors.toList()); 11// => [2015/01, 2015/02, 2015/03, 2015/04, 2015/05, 2015/06, 2015/07, 2015/08, 2015/09, 2015/10, 2015/11, 2015/12, 2016/01]

2015/01から1月ごと加算する年月の無限ストリームを生成して、13個に制限し、フォーマットで文字列に変換しています。


(追記2)

上記の13(月数)を年月から算出するには下記のようにします。
(sipadan2003さんにご指摘いただきました。)
こうすると、YearMonth.of(2015, 1)が複数登場してしまうので、変数startYMなどに代入して重複を解消してください。

lang

1// import java.time.YearMonth; 2// import java.time.temporal.ChronoUnit; 3 4long monthCount = YearMonth.of(2015, 1).until(YearMonth.of(2016, 1), ChronoUnit.MONTHS) + 1; 5// => 13 6 7// これもほぼ同じ 8// long monthCount = ChronoUnit.MONTHS.between(YearMonth.of(2015, 1), YearMonth.of(2016, 1)) + 1;

Java7以前なら、素直にforループで書いた方が無難です。

投稿2016/06/24 17:24

編集2016/06/25 09:54
argius

総合スコア9390

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

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

sobue

2016/06/24 23:16

加算する月数はベタ打ちしないとだめなのですか?
argius

2016/06/24 23:35

ベタ打ちというのはどれのことでしょうか?
退会済みユーザー

退会済みユーザー

2016/06/25 03:44 編集

limit(13)のことでしょう。 通常、「13ヶ月分出力する」というより、「いつからいつまでを出力する」が多いでしょう。
argius

2016/06/25 04:07

sipadan2003さん ご指摘ありがとうございます。 既に月数を計算済みと思い込んでしまいました。 ハードコーディングという連想もできず。ボケてました。
sobue

2016/06/27 13:09

今回、ベストアンサーは非常に悩みました。最も簡潔だと思ったコードにベストアンサーとさせていただきました。今回はjava8ではないので皆さんにはjava8での回答をしていただきましたので、申し訳ありませんでした。きちんとバージョンも伝えるようにします。答えていただいたjava8に関しては次回使用することがあれば使用させていただきます。ありがとうございます。
guest

0

何をするプログラムかいまいちわからないんですが、結局この処理の後に残るのは文字列だけですよね?
1 年は 12 カ月と決まってるんだから、カレンダーへの変換は要らないんじゃないですか?

投稿2016/06/24 14:16

Zuishin

総合スコア28660

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

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

sobue

2016/06/24 14:21

最終的にはエクセルに出力して表にしたかったのです。 1年はもちろん12ヶ月と決まっていますがそれをリスト化して出力したかったのです
Zuishin

2016/06/24 15:18

わざわざカレンダーに変換しなくても、数字を 1 ずつ増やしながら順に出力して 13 になったら年を 1 増やして月を 1 にするだけでいいんじゃないでしょうか?
Zuishin

2016/06/24 15:51

可読性を落としている原因は主に二つあると思います。 一つは文字列とカレンダーと数字の三種類のデータの変換が入り混じっていること。swordone さんの示されたように、全部 int にまとめるのは大変効果的です。 もう一つは main 文だけで全部やっていること。 機能を関数にまとめることでかなり見通しが良くなるはずです。
guest

0

難読化している最大の要因は、カレンダーから文字列への変換ですね。
SimpleDateFormatを使えば、このインスタンスを1つ用意しておくだけで、文字列変換が1文で書けます。

java

1DateFormat format = new SimpleDateFormat("yyyyMM"); 2String now = format.format(calendar.getTime());

なお、他の方も回答していますが、年月を管理するのにわざわざCalendarを使う必要は無いのでは?
この操作に限定するなら、intで年と月をそれぞれ管理すればいいのでは?

java

1int fromym = 201501; 2int toym = 201601 3 4int year = fromym / 100; 5int month = fromym % 100; 6int cal = fromym; 7while(cal <= toym){ 8 System.out.println(cal); 9 month++; 10 if(month > 12){ 11 year += month / 12; 12 month %= 12; 13 } 14 cal = year * 100 + month; 15}

また、Calendarはバグがあるなど潜在的な問題があるので、Java8のAPIを使うことをおすすめします。

java

1DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuuMM"); 2 3//ベースが文字列なら、上のformatterを使ってparseメソッドを使うがここでは省略 4YearMonth from = YearMonth.of(2015, 1); 5YearMonth to = YearMonth.of(2016, 1); 6ArrayList<YearMonth> yms = new ArrayList<>(); 7 8YearMonth now = from; 9 10while(!to.isBefore(now)){ 11 yms.add(now); 12 now = now.plus(1, ChronoUnit.MONTHS); 13} 14 15for(YearMonth ym : yms){ 16 System.out.println(formatter.format(ym)); 17}

投稿2016/06/24 12:19

編集2016/06/24 17:06
swordone

総合スコア20651

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

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

sobue

2016/06/24 15:30

いつも、詳しい回答ありがとうございます。int型も考えてはいたのですがなにをしているかがわかりにくいかな?と瞬間的に選択肢から消してました。全ての可能性を捨てずに考えたいと思います。
guest

0

年月表示を月数に変換して処理する例を示します。
(ruby でかいてますが、処理方法は伝わると思います)
時分表記を分単位に置き換えて処理するのと同様です。(
1時間2分を 62分と置き換える、 逆に 72 分は 1時間12分と置き換える)
a.rb

ruby

1fromym = 201501 2toym = 201601 3 4from_m = (fromym / 100) * 12 + (fromym % 100 - 1) 5to_m = (toym / 100) * 12 + (toym % 100 - 1) 6 7(from_m..to_m).each do |m| 8 puts((m / 12) * 100 + (m % 12 + 1)) 9end

実行結果

$ ruby a.rb 201501 201502 201503 201504 201505 201506 201507 201508 201509 201510 201511 201512 201601

投稿2016/06/28 22:53

katoy

総合スコア22324

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

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

0

###コード例 (Java 8)

性能は悪いですが、コードの可読性は良いと思います。

Java

1public static void main(String[] args) { 2 final SimpleDateFormat format = new SimpleDateFormat("yyyy/MM"); 3 final Calendar to = new GregorianCalendar(2016, 1, 1); 4 final Calendar cal = new GregorianCalendar(2015, 0, 1); 5 final List<String> yms = new ArrayList<>(); 6 do { 7 yms.add(format.format(cal.getTime())); 8 cal.add(Calendar.MONTH, 1); 9 }while(cal.before(to)); 10 yms.forEach(System.out::println); 11}

###実行結果

2015/01 2015/02 : 2015/12 2016/01

投稿2016/06/24 14:50

編集2016/06/24 15:09
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

swordone

2016/06/24 15:15

なぜわざわざJava8を持ちだしたのにCalendarクラスなのか
退会済みユーザー

退会済みユーザー

2016/06/25 03:23 編集

質問者が「カレンダークラス」と要件を出しているからです。 DateTime APIを使うことには賛成ですが、質問者は可読性にもこだわっているようですから、それは議論点でしょう。ともあれ、サンプルを出してみたわけです。
guest

0

年月を受け取って、次の年月を返す関数作ったら?
で、返ってきたのが最終年月になるまでループ
みたいな感じで。

投稿2016/06/24 10:29

takasima20

総合スコア7458

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問