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

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

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

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

Q&A

解決済

6回答

1995閲覧

リスト内の値の比較をして出力したい

Kokekokko1

総合スコア7

Java

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

0グッド

0クリップ

投稿2018/05/07 11:10

前提・実現したいこと

Javaの学習をしており練習に以下のようなプログラムを作成しようとしています
1.入力した値を比較し最もゼロに近く値を出力する
2.正と負の値で絶対値が同じ場合(2とー2など)、正の値を出力する

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

期待通りの出力ではなく、入力していない[-1]が出力される場合がある

入力した正負の値を一度絶対値にしてから比較してより0に近いものを出力しようとしているのですが
入力した数字によって正しい出力が得られる場合と、そうでない場合が発生しています。
例えば、
入力回数: 3
入力: 3,-2,2,3
とした場合、出力が[-1]となってしまいます
しかし
入力回数: 3
入力: 3,-2,2,1
とした場合であれば、期待通り[1]が出力されます

該当のソースコード

Java

import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Scanner; public class Temperatures { public static void main(String args[]) { Scanner in = new Scanner(System.in); int n = in.nextInt(); // the number of temperatures to analyse List<Integer> Minus = new ArrayList<>(); List<Integer> Plus = new ArrayList<>(); int answer =0; for (int i = 0; i < n; i++) { int t = in.nextInt(); if(t<0) { Minus.add(t); }else if(t>0) { Plus.add(t); } } Collections.sort(Plus); Collections.sort(Minus); if(Minus.isEmpty()) { answer=Plus.get(0); } else if(Plus.isEmpty()) { answer=Minus.get(Minus.size()); } else { if(Math.abs(Plus.get(0))>Math.abs(Minus.size())) answer =Minus.size()*-1; else if(Math.abs(Plus.get(0))<Math.abs(Minus.size())) answer =Plus.get(0); else if(Math.abs(Plus.get(0))==Math.abs(Minus.size())) answer =Plus.get(0); } System.out.println(answer);//出力が-1になる } }

この問題の発生理由と解決策を教えていただけませんか?
宜しくお願いします

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

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

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

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

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

a_saitoh

2018/05/07 15:47

入力されたデータをListなどに格納して保持することは必須なのでしょうか?絶対値が最も小さい値を出すだけなら、格納する必要はないとおもうのですが。
guest

回答6

0

別解として記載します。

まず、絶対値を扱う時は負の最大値Integer.MIN_VALUE or Long.MIN_VALUEを意識する必要があります
参考 -> Math#abs

int値の絶対値を返します。引数が負でない場合は引数そのものを返します。負のときは、その正負を逆にした値を返します。
引数がInteger.MIN_VALUEの値(intの最小値)と等しい場合は、結果も同じ値(負の値)になります。

質問文の要求仕様として入力データを出力表示しないので、MinusPlusで List を分ける必要がないのではと思います。そして、Collections.sort(Minus);の引数に比較関数:Comparatorを渡せます。

Java

1List<Integer> sequence = Arrays.asList(3, -2, 2, 3); 2Collections.sort(sequence, (x, y) -> { 3// 比較処理 4});

数字の比較にはInteger.compareが使えます。

投稿2018/05/07 13:48

編集2018/05/07 13:50
umyu

総合スコア5846

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

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

LouiS0616

2018/05/07 14:50

> 絶対値を扱う時は負の最大値Integer.MIN_VALUE or Long.MIN_VALUEを意識する必要があります あー... 見逃しがちですが、非常に大事な点ですね。 趣味グラマとしてはなかなかこういう観点が持てないので、非常に参考になります。 ただ、クラス名がTemperaturesであることを見るに、Integer.MIN_VALUEの入力はあり得ないと仮定してしまっても良いような気もします。
umyu

2018/05/07 14:53

>LouiS0616さんへ クラス名を絶賛無視して、数字の正しい比較方法を熱く語ってしまいました。。。
LouiS0616

2018/05/07 15:03

そゆこともあります。。。 私の書いたgetNearlyZeroメソッドについては、最初に次の処理を追加すれば問題ないでしょうか。 if(a == Integer.MIN_VALUE) return b; if(b == Integer.MIN_VALUE) return a;
umyu

2018/05/07 15:11

>LouiS0616さんへ それで大丈夫ですが、今回の件にいえばMath.min(a,b)を計算して結果がInteger.MIN_VALUEだったら不正データとして例外を投げちゃうのも一つの手かと。
LouiS0616

2018/05/07 15:21

それが良さそうですね。ありがとうございます。
guest

0

ベストアンサー

Java

if(Math.abs(Plus.get(0))>Math.abs(Minus.size()))
answer =Minus.size()*-1;

ここでMinus.size() * -1をanswerに放り込んでいるのが直接的原因では。

そもそも

難しく考えすぎな気もします。

Java

1int n = 入力; 2int result = 入力; // 暫定的に『ゼロに一番近い値』とみなす。 3 4for(n回繰り返す) { 5 int num = 入力; 6 7 numとresultの絶対値をそれぞれ計算; 8 if(numの絶対値 < resultの絶対値) { 9 result = num; 10 } 11 else if(numの絶対値 > resultの絶対値) { 12 // 更新は不要 13 } 14 else { 15 result = numとresultのうち大きい方; 16 } 17}

変数名が適当ですが、悪しからず。

さらに

メソッドを利用するともっと簡潔です。

Java

1// 絶対値がゼロに近い方を返す。絶対値が同じ場合正の数を返す。 2static int getNearlyZero(int a, int b) { 3 aの絶対値とbの絶対値をそれぞれ計算; 4 5 if(aの絶対値 < bの絶対値) return a; 6 if(aの絶対値 > bの絶対値) return b; 7 8 return aとbのうち大きい方; 9} 10 11public static void main(String[] args) { 12 ... 13 14 int result = ...; 15 for(...) { 16 int num = ...; 17 result = getNearlyZero(result, num); 18 } 19}

投稿2018/05/07 11:19

編集2018/05/07 13:03
LouiS0616

総合スコア35660

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

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

Kokekokko1

2018/05/10 11:25

解決法及びアドバイスをいただき有難うございました。他の方々もたくさんのアドバイスを下さり現在調べながら消化吸収させて頂いておりますが、一先ず、リストを使わない、メソッド使うなど、私のコードをもとに分かりやすい回答とブラッシュアップを提示していただいたLouiS0616さんをベストアンサーとさせて頂きます。 あらためて有難うございました。
guest

0

java

1import static java.util.Comparator.*; 2 3import java.util.Scanner; 4import java.util.stream.IntStream; 5 6public class Q125097 { 7 8 public static void main(String[] args) { 9 try (Scanner s = new Scanner(System.in)) { 10 int n = s.nextInt(); 11 int x = IntStream.generate(() -> s.nextInt()).limit(n).boxed() 12 .min(comparing((Integer i) -> Math.abs(i)).thenComparing(reverseOrder())).get(); 13 System.out.println(x); 14 } 15 16 } 17 18} 19

投稿2018/05/07 16:31

swordone

総合スコア20651

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

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

Kokekokko1

2018/05/10 11:25

なるほど。このような書き方もあったのですね。非常に参考になります。ラムダ式、StreamAPIを用いたコーディングは、これまで挑戦したことがなかったのですが、ここまで端的に書けるものなんですね。ぜひとも今後の課題として理解を深めていこうと思います。
guest

0

質問文のコードの
answer=Minus.get(Minus.size());

if(Math.abs(Plus.get(0))>Math.abs(Minus.size()))

の Minus.size() は Munus.get(Minus.size() -1) の間違いとおもわれます。

Integer をつかって、 入力値がない場合を null であつかうようにする、
0 以外の入力をすべて List に保持せずに、それまでの入力の正の最小値と負の最大値だけを保持するようにする
という方針で書き換えてみました。
もっと短く書けるとは思いますが、とりあえず素直に条件判定を書いていきました。

java

1import java.util.Scanner; 2 3public class Temperatures { 4 5 public static void main(String args[]) { 6 Scanner in = new Scanner(System.in); 7 int n = in.nextInt(); // the number of temperatures to analyse 8 Integer minus_max = null; // その時点での 正値の最小値 9 Integer plus_min = null; // その時点での 負値の最大値 10 11 for (int i = 0; i < n; i++) { 12 int t = in.nextInt(); 13 if (0 < t) { 14 if (plus_min == null || t < plus_min) { 15 plus_min = t; 16 } 17 } else if (t < 0) { 18 if (minus_max == null || minus_max < t) { 19 minus_max = t; 20 } 21 } 22 } 23 // System.out.println("" + plus_min + "," + minus_max); 24 25 Integer answer = null; 26 if (minus_max == null && plus_min == null) { 27 answer = null; 28 } else if (minus_max == null) { 29 answer = plus_min; 30 } else if (plus_min == null) { 31 answer = minus_max; 32 } else { 33 if ((minus_max * (-1)) < plus_min) { 34 answer = minus_max; 35 } else { 36 answer = plus_min; 37 } 38 } 39 40 if (answer != null) { 41 System.out.println(answer); 42 } 43 } 44}

実行例
イメージ説明

投稿2018/05/07 22:07

katoy

総合スコア22324

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

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

0

ソートして最初の要素を出力

java

1import java.util.ArrayList; 2import java.util.List; 3import java.util.Scanner; 4 5public class Temperatures { 6 public static void main(String args[]) { 7 List<Integer> numbers = new ArrayList<>(); 8 9 Scanner in = new Scanner(System.in); 10 int n = in.nextInt(); 11 for (int i = 0; i < n; i++) { 12 int t = in.nextInt(); 13 numbers.add(t); 14 } 15 16 numbers.sort((x, y) -> { 17 int d = Math.abs(x) - Math.abs(y); 18 if (d != 0) return d; 19 return Integer.compare(y, x); 20 }); 21 22 System.out.println(numbers.get(0)); 23 } 24}

投稿2018/05/07 14:27

編集2018/05/07 15:20
hichon

総合スコア5737

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

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

umyu

2018/05/07 14:35 編集

>hichonさんへ d = x - y;とすると、xとyの差がInteger.MAX_VALUEを超える時に出力結果が正しくありません。 これは符号付きの数字の差はその数字型の整数値で表せないために発生します。 Integer.compareがあるので、そちらを使って頂くほうがよいかと思いました。
umyu

2018/05/07 14:48 編集

以下のテストデータで再現できるかと。 List<Integer> numbers= Arrays.asList(Integer.MIN_VALUE+3, Integer.MAX_VALUE-2); for(int x:numbers) { System.out.println(x); }
hichon

2018/05/07 14:59

なるほど、オーバーフローの可能性がありますね。修正しました。
umyu

2018/05/07 15:03

>hichonさんへ お手数をおかけしました。修正ありがとうございました。
hichon

2018/05/07 15:16 編集

良く考えると、Math.abs(Integer.MIN_VALUE)もオーバーフローしますね。これは、入力値を制限した方が良いかも。
umyu

2018/05/07 15:18

>hichonさんへ hichonさんへコメントした後にLouiS0616さんから指摘を受けたのですが、クラス名がTemperatures (気温)だからそもそも論としてInteger.MIN_VALUEの値が入らないのではないかという話が。。 修正対応していただいて、すごく申し訳ないのです。。
hichon

2018/05/07 15:24

なんとクラス名は見落としていました。しかし、Integer.compareのおかげでさらにコードが短くなりました。
guest

0

入力回数がわかっているのなら配列を使うこともできます。
(i)入力回数をnとしサイズ2 * nの配列を準備します。(名前をdataにしておきます。)

(ii)0行目には入力されたデータを格納し、1行目にはその絶対値を格納します。

(例)入力回数 n = 3
入力された整数 3 1 -5の時 [][]dataは 

3 1 -5 3 1 5

となっています。

(iii)絶対値の中で最小値をとります。(今回は1です。)

(iv)絶対値の中の最小値の配列の番号を使って求めたいものを表示します。

今回は最小値が1でしたがそれはdata[1][1]です。
ということは、求めたい「最も0に近い整数」は**data[0][1]**と なっているはずです。

私が、書いたソースコードを載せておきます。

Java

1import java.util.*; 2 3public class Main { 4 public static void main(String[] args) { 5 Scanner sc = new Scanner(System.in); 6 int n = sc.nextInt(); 7 int [][]data = new int[2][n]; 8 int min; 9 int []min2 = {0,0}; 10 int []count = {0,0}; 11 for(int i = 0; i < n; i++){ 12 data[0][i] = sc.nextInt(); 13 data[1][i] = Math.abs(data[0][i]); 14 min = data[1][0]; 15 if(min >= data[1][i]){ 16 if(data[1][i] >= 0){ 17 min2[0] = data[0][i]; 18 count[0]++; 19 } 20 else{ 21 min2[1] = data[0][i]; 22 count[1]++; 23 } 24 } 25 } 26 27 int flag = 0; 28 for(int i = 0; i < 2; i++){//0に最も近い整数が1つの時(正、負のどちらか片方だけある) 29 if(count[i] == 0){ 30 flag = 1; 31 System.out.println(min2[1 - i]); 32 } 33 } 34 if(flag == 0){//0に最も近い整数が2つの時(正、負両方あり) 35 System.out.println(min2[0]); 36 } 37 } 38}

<入力例>
7
-1
4
-2
3
6
5
1
<出力例>
1

投稿2018/05/07 12:28

編集2018/05/08 02:05
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

umyu

2018/05/07 14:21

1点目,入力数値データを2乗するとIntger.MAX_VALUE /2 以上のデータでオーバーフローしてしまいます。そのため、不正な出力結果になります。以下の入力データでテストしてみてくださいな。 3 1073741824 1073741 1 今回の件に関しては、Math#absとを使った方がよいのではーと思いますー。 2点目、入力された数字が全部100以上だとmin =100の初期値によって0が2個出力されるのではと。 3 101 120 956 自作すると不具合を入れやすいので、テスト済みの標準ライブラリを使うか、データの境界値のテストを意識されたほうが良いのではと個人的に思いました。 Stars1024さんの真摯な回答の点は学ばないと行けないと思っているので、その点だけ。
退会済みユーザー

退会済みユーザー

2018/05/08 04:49 編集

***********************************
退会済みユーザー

退会済みユーザー

2018/05/08 01:26

入力される整数がどれくらいなのかわからなかったのでとりあえずこのような形で書きました。
退会済みユーザー

退会済みユーザー

2018/05/08 02:06

訂正しました。2乗のところを絶対値に変えました。あと最小値のところは初期値を入力した 値を使いました。
umyu

2018/05/08 08:35

>Stars1024さんへ ソースコードを変更して頂き、ありがとうございました。
退会済みユーザー

退会済みユーザー

2018/05/08 13:11 編集

>umyuさんへ こちらこそご指摘ありがとうございました。オーバーフローについて考えてなかったので 勉強になりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問