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

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

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

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

コマンド

コマンドとは特定のタスクを行う為に、コンピュータープログラムへ提示する指示文です。多くの場合、コマンドはShellやcmdようなコマンドラインインターフェイスに対する指示文を指します。

Q&A

解決済

7回答

18960閲覧

星座の判別をIF文を大量に使わずに判別する方法

ryuxx

総合スコア18

Java

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

コマンド

コマンドとは特定のタスクを行う為に、コンピュータープログラムへ提示する指示文です。多くの場合、コマンドはShellやcmdようなコマンドラインインターフェイスに対する指示文を指します。

3グッド

8クリップ

投稿2019/10/14 10:36

前提・実現したいこと

現在のソースだと、IF文が大量にあるので、見栄えが悪く、ソースの修正があった場合、修正行が多くなることがあると思うので、星座判別の規則性を使ってソースを改変したいのですが、規則がわからず苦戦中
星座の判別について、javaのコマンドライン引数を使って星座を判別します。
コマンドライン引数は、
例)1201
1003

Case文も使用せずにソースの改変を行いたい

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

エラーは現在ありません。

該当のソースコード

Java

1public class Constellation { 2 public static void main(String[] args) { 3 // 入力値MMDD(想定) 4 String myDay = args[0]; 5 try { 6 int month = Integer.parseInt(myDay.substring(0, 2)); 7 int day = Integer.parseInt(myDay.substring(2, 4)); 8 // 星座名取得. 9 String seizaName = getSeiza(month, day); 10 if (seizaName == null) { 11 System.out.println("日付が正しくない"); 12 } 13 System.out.println(seizaName); 14 15 } catch (Exception e) { 16 System.out.println("日付が正しくない"); 17 } 18 } 19 20 /** 21 * 星座名取得. 22 * 23 * @param month24 * @param day25 * @return seizaName 星座名 26 */ 27 public static String getSeiza(int month, int day) { 28 String seizaName = null; 29 if (month < 13) { 30 if (month == 3 && day >= 21 || month == 4 && day <= 19) { 31 return seizaName = "牡羊座"; 32 } else if (month == 4 && day >= 20 || month == 5 && day <= 20) { 33 return seizaName = "牡牛座"; 34 } else if (month == 5 && day >= 21 || month == 6 && day <= 21) { 35 return seizaName = "双子座"; 36 } else if (month == 6 && day >= 22 || month == 7 && day <= 22) { 37 return seizaName = "蟹座"; 38 } else if (month == 7 && day >= 23 || month == 8 && day <= 22) { 39 return seizaName = "しし座"; 40 } else if (month == 8 && day >= 23 || month == 9 && day <= 22) { 41 return seizaName = "乙女座"; 42 } else if (month == 9 && day >= 23 || month == 10 && day <= 23) { 43 return seizaName = "てんびん座"; 44 } else if (month == 10 && day >= 24 || month == 11 && day <= 22) { 45 return seizaName = "蠍座"; 46 } else if (month == 11 && day >= 23 || month == 12 && day <= 21) { 47 return seizaName = "射手座"; 48 } else if (month == 12 && day >= 22 || month == 1 && day <= 19) { 49 return seizaName = "山羊座"; 50 } else if (month == 1 && day >= 20 || month == 2 && day <= 18) { 51 return seizaName = "水瓶座"; 52 } else { 53 return seizaName = "魚座"; 54 } 55 } else { 56 return seizaName; 57 } 58 } 59}

補足情報(FW/ツールのバージョンなど)

DrqYuto, fa11enprince, mkzk👍を押しています

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

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

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

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

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

swordone

2019/10/14 12:45

とりあえず、getSeizaで使ってるローカル変数seizaNameは不要。 あと、日付の正当性はチェックしなくてよいのでしょうか(1032の様な入力)?
guest

回答7

0

ベストアンサー

基本的に配列を使って「月」で割り振る。例えば1月は基本的に山羊座と考える。
月ごとに星座が切り替わる日付も配列で管理し、ある月でその日以降の日であれば月を1増やす。1月は20日以降が水瓶座なので、それを「2月」として扱う。
12月の次の月になった場合は1月に戻す。

java

1 public static String getSeiza(int month, int day) { 2 String[] seizaName = {"山羊座", "水瓶座", "魚座", "牡羊座", "牡牛座", "双子座", 3 "蟹座", "しし座", "乙女座", "てんびん座", "蠍座", "射手座"}; 4 int[] border = {20, 19, 21, 20, 21, 22, 23, 23, 23, 24, 23, 22}; 5 6 int index = month - 1; 7 if(day >= border[index]){ 8 index++; 9 } 10 if(index == 12){ 11 index = 0; 12 } 13 return seizaName[index]; 14}

また、Java8以降ならMonthDayDateTimeFormatterを使って、入力された日付の妥当性チェックもまとめて行うこともできます。

java

1public class Constellation { 2 public static void main(String[] args) { 3 try { 4 // 日付変換 不適当な入力であればDateTimeParseException発生 5 MonthDay date = MonthDay.parse(args[0], DateTimeFormatter.ofPattern("MMdd")); 6 // 星座名取得. 7 String seizaName = getSeiza(date); 8 System.out.println(seizaName); 9 10 } catch (DateTimeParseException e) { 11 System.out.println("日付が正しくない"); 12 } 13 } 14 15 // 星座名取得. 16 public static String getSeiza(MonthDay date) { 17 String[] seizaName = {"山羊座", "水瓶座", "魚座", "牡羊座", "牡牛座", "双子座", 18 "蟹座", "しし座", "乙女座", "てんびん座", "蠍座", "射手座"}; 19 // 各星座の年内の最後の月日 20 MonthDay[] lastDays = {MonthDay.of(1, 19), MonthDay.of(2, 18), MonthDay.of(3, 20), 21 MonthDay.of(4, 19), MonthDay.of(5, 20), MonthDay.of(6, 21), 22 MonthDay.of(7, 22), MonthDay.of(8, 22), MonthDay.of(9, 22), 23 MonthDay.of(10, 23), MonthDay.of(11, 22), MonthDay.of(12, 21)}; 24 for (int i = 0; i < lastDays.length; i++) { 25 if (date.compareTo(lastDays[i]) <= 0) { 26 return seizaName[i]; 27 } 28 } 29 // 12月22日以降だった場合 30 return seizaName[0]; 31 } 32}

また、TreeMapを使えばこんな書き方もできます(Map生成の書き方はJava9以降)。
ただここまで長くなると、static importを使わずに書くのはつらいし見づらい…

java

1 // 星座名取得. 2 public static String getSeiza(MonthDay date) { 3 TreeMap<MonthDay, String> lastDayOfSeiza = new TreeMap<>( 4 Map.ofEntries(Map.entry(MonthDay.of(1, 19), "山羊座"), Map.entry(MonthDay.of(2, 18), "水瓶座"), 5 Map.entry(MonthDay.of(3, 20), "魚座"), Map.entry(MonthDay.of(4, 19), "牡羊座"), 6 Map.entry(MonthDay.of(5, 20), "牡牛座"), Map.entry(MonthDay.of(6, 21), "双子座"), 7 Map.entry(MonthDay.of(7, 22), "蟹座"), Map.entry(MonthDay.of(8, 22), "しし座"), 8 Map.entry(MonthDay.of(9, 22), "乙女座"), Map.entry(MonthDay.of(10, 23), "てんびん座"), 9 Map.entry(MonthDay.of(11, 22), "蠍座"), Map.entry(MonthDay.of(12, 21), "射手座"), 10 Map.entry(MonthDay.of(12, 31), "山羊座") 11 )); 12 13 return lastDayOfSeiza.ceilingEntry(date).getValue(); 14 } 15

投稿2019/10/14 13:07

編集2019/10/15 03:53
swordone

総合スコア20649

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

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

jimbe

2019/10/14 18:52

> Java8以降ならMonthDayと... そんなクラスがあったんですね, 知りませんでしたありがとうございます.
swordone

2019/10/14 19:18

あったか自信がなかったので、なかったら適当に2020年などのうるう年指定して…とか考えてましたw
ryuxx

2019/10/15 07:22

>Java8以降ならMonthDayと そんなクラスがあったの初めて知りました。 よりシンプルにかけるみたいで勉強になりました。 ベストアンサーにさせていただきます
guest

0

0119 山羊座 0218 水瓶座 0320 魚座 0419 牡羊座 0520 牡牛座 0621 双子座 0722 蟹座 0822 獅子座 0922 乙女座 1023 天秤座 1122 蠍座 1221 射手座 1300 山羊座

このデータから配列を二つ作ります。
一つは Integer 型で、119, 218, 320, ... が入ります。
もう一つは String 型で、山羊座, 水瓶座, 魚座, ... が入ります。
文字列をコードで分割しなくても、最初から配列としてコーディングしてもいいです。

次に調べたい日付の月を 100 倍して日と足します。
たとえば 10 月 14 日であれば 1014 となります。

数値の配列の頭から調べて行き、1014 が初めてその数値以下になった時点で対応する文字列を返します。
1014 の場合、1023 以下になるので、天秤座を返すことになります。

投稿2019/10/14 11:28

編集2019/10/14 11:30
Zuishin

総合スコア28656

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

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

0

swordoneさんの改良してみました。if文なしでやってみました
C#でテストしてないんで正しいかどうか分からないですけど…。

C#

1 public static string getSeiza(int month, int day) 2 { 3 string[,] seizaName = 4 { 5 { "山羊座", "水瓶座", }, 6 { "水瓶座", "魚座", }, 7 { "魚座", "牡羊座", }, 8 { "牡羊座", "牡牛座", }, 9 { "牡牛座", "双子座", }, 10 { "双子座", "蟹座", }, 11 { "蟹座", "しし座", }, 12 { "しし座", "乙女座", }, 13 { "乙女座", "てんびん座", }, 14 { "てんびん座", "蠍座", }, 15 { "蠍座", "射手座", }, 16 { "射手座", "山羊座", }, 17 }; 18 int[] border = { 20, 19, 21, 20, 21, 22, 23, 23, 23, 24, 23, 22 }; 19 20 int index = month - 1; 21 return seizaName[index, (int)(day / border[index])]; 22 }

投稿2019/10/22 02:39

kikiinu

総合スコア21

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

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

Zuishin

2019/10/22 02:58 編集

申し訳ないけど改悪にしか見えません。 それとここで言うのもなんですが、過去の質問が解決したなら解決済みにしてください。してないのなら質問を編集して既存の回答でなぜ解決しないのかを書いてください。
guest

0

入力の形式がどうで、最終的にどういう結果を得たいのか、イマイチ分かりませんが…

配列を3種類用意します。
1つめ:要素が12個、月から日にちの配列を選ぶためのインデックスを得る。
2つ目:12個の配列、それぞれの月ごとに日数分の要素を持つ。
それぞれの日にちから星座のインデックスを取り出します。
3つ目:星座のインデックスから星座名の文字列を取り出す。

月、日の範囲をチェックしない、うるう年を判定しないなら、 if 文を書かなくてもできると思います。
星座名の文字列が不要なら、3つ目は要らない。

投稿2019/10/15 04:52

nob.

総合スコア711

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

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

ryuxx

2019/10/15 07:19

入力形式は:1201 みたいな感じでargs[0]に入る 出力結果として 入力された月日を算出して、正座名が出力される
guest

0

enum にします.

java

1public class Main { 2 public static void main(String args[]) { 3 String myDay = args[0]; 4 try { 5 int month = Integer.parseInt(myDay.substring(0, 2)); 6 int day = Integer.parseInt(myDay.substring(2, 4)); 7 MonthDay monthDay = MonthDay.of(month, day); 8 // 星座取得. 9 Zodiac constellation = Zodiac.get(monthDay); 10 System.out.println(constellation.getJName()); 11 } catch (DateTimeException e) { 12 System.out.println("日付が正しくない"); 13 } 14 } 15 16 enum Zodiac { 17 Aries("牡羊座", 3,21, 4,19), 18 Taurus("牡牛座", 4,20, 5,20), 19 Gemini("双子座", 5,21, 6,21), 20 Cancer("蟹座", 6,22, 7,22), 21 Leo("獅子座", 7,23, 8,22), 22 Virgo("乙女座", 8,23, 9,22), 23 Libra("天秤座", 9,23, 10,23), 24 Scorpius("蠍座", 10,24, 11,22), 25 Sagittarius("射手座", 11,23, 12,21), 26 Capricornus("山羊座", 12,22, 1,19) { 27 boolean contains(MonthDay target) { //年をまたがるのでこれだけ式が違う 28 return start.compareTo(target) <= 0 || target.compareTo(end) <= 0; 29 } 30 }, 31 Aquarius("水瓶座", 1,20, 2,18), 32 Pisces("魚座", 2,19, 3,20); 33 34 protected String jname; 35 protected MonthDay start, end; 36 Zodiac(String jname, int startMonth, int startDay, int endMonth, int endDay) { 37 this.jname = jname; 38 this.start = MonthDay.of(startMonth, startDay); 39 this.end = MonthDay.of(endMonth, endDay); 40 } 41 String getJName() { return jname; } 42 boolean contains(MonthDay target) { 43 return start.compareTo(target) <= 0 && target.compareTo(end) <= 0; 44 } 45 46 static Zodiac get(MonthDay target) { 47 for(Zodiac z : values()) if(z.contains(target)) return z; 48 throw new DateTimeException("定義に洩れがあるようです. target="+target); 49 } 50 } 51}

投稿2019/10/14 13:40

編集2019/10/15 14:19
jimbe

総合スコア12545

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

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

0

星座を配列に入れて、日付からそのインデックスを算出すればいけますね

投稿2019/10/14 10:54

y_waiwai

総合スコア87719

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

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

ryuxx

2019/10/14 10:58

日付からインデックスを算出するということは、月の部分は一切判別条件に入れないということでしょうか?
y_waiwai

2019/10/14 11:06

もちろん月も入りますよ
ryuxx

2019/10/14 11:11

ピンと来ないので、もう少しヒントをご教示お願いします。。
guest

0

こういった問題は配列だと思います。
まずはデータ構造を規定します。
javaに明るくないので、
データ構造をjsonで表します。

json

1[{ 2 "seiza": "山羊座", 3 "startMonth": 12, 4 "startDay": 22, 5 "endMonth": 1, 6 "endDay": 21, 7},{ 8 "seiza": "水瓶座", 9 "startMonth": 1, 10 "startDay": 22, 11 "endMonth": 2, 12 "endDay": 21, 13},...全ての星座データ]

その後、この配列の中から条件に合致するデータを探す関数を定義します。
例えばjavascriptであれば配列にfind関数があるので、
comparatorを定義するだけです。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/find

この方法の良いところは応用がきくところと宣言的であることだと思います。
まず、星座以外の場合はこのデータが増える場合がありますが、
ロジックは変更せずに配列のデータを追加するのみになります。

その他判断ロジックが増える場合等は配列に別のデータを追加し、
findに渡す関数のロジックを少し変更するのみです。

投稿2019/10/24 06:10

topiinopii

総合スコア47

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問