配列のfor文の中にif文を入れる文について – java array

質問:


閲覧ありがとうございます。
現在java独学中のプログラミング初心者です。

キーボードから数字一文字を入力し、その数字が配列の中の数字のどれかと一致していれば「アタリ!」、一致していなければ「ハズレ」と表示されるコードを書きたいのですがどう書けば良いのかわからず質問させて頂きました。

public class Aaaa {

    public static void main(String[] args) {
        // TODO 自動生成されたメソッド・スタブ
        int[] numbers = {3,4,9};

        System.out.println("1行の数字を入力してください");
        int input=new java.util.Scanner(System.in).nextInt();


        for(int a:numbers) {
            if(a==input) {
                System.out.println("アタリ!");
            }   
            if(a!=input) {
                System.out.println("ハズレ");
            }
        }

    }
}

こちらが私が書いたコードなのですが、これだと「9」と入力した場合、

ハズレ
ハズレ
アタリ!

と表示されてしまいます。
どのように改善すればアタリ!とだけ表示されるのでしょうか?

初歩的な質問だとは思いますが、どなたか教えていただけると助かります。
宜しくお願い致します。

質問者: user29166

解決策

numbers に含まれるすべての要素と等しくないと分かってから初めて「ハズレ」と出力するようにしてください。

実験

どのようにプログラムが動いているか、具体的な値を使って実験してみましょう。

たとえば入力された数字が 9 だったとします。これは {3, 4, 9} に含まれているので、期待している出力は「アタリ!」です。

質問文中にあるプログラムの for 文を見てみます。

for(int a:numbers) {
    if(a==input) {
        System.out.println("アタリ!");
    }   
    if(a!=input) {
        System.out.println("ハズレ");
    }
}

この for では、配列 numbers 、つまり {3, 4, 9} を頭から順番に試すことで、9 と等しいかどうか検査しようとしています。

さて、{3, 4, 9} の先頭は 3 なので、まず a3 が代入され、1 つ目の if 文のところで a == input であるかどうか確かめられます。39 は等しくないので、この if 文の中身は実行されません。

次に 2 つ目の if 文で a != input であるか確かめられます。これは真なので if 文の中身が実行され、「ハズレ」と出力されます。……あれ、期待していた動作と異なる動き方になってしまいました 🙁

また、この後 for 文の最初に戻り、a4 が代入されて「ハズレ」が出力されます。最後に a9 が代入され、今回は a == input なので「アタリ!」が出力されます。

したがって全体的には実際の出力が

ハズレ
ハズレ
アタリ!

と 3 行に渡って出力されることになってしまいます。

原因

こうなってしまう原因は、配列 numbers の中身 すべて に対して「等しいかどうか」を調べるより に「ハズレ」と出力してしまうことにあります。現状のプログラムだと、各要素 1 つだけの比較のみを元にして何回も「アタリ!」「ハズレ」を出力してしまっているのです。

解決策 (再掲)

したがって、numbers に含まれるすべての要素と等しくないと分かってから初めて「ハズレ」と出力するようすれば良いのです。

たとえば for 文を回す前に「アタリだったかどうか」を示す boolean 型の変数を用意しておいて、false で初期化しておきます。そして for 文の中ではこの変数を弄ることしかせず、for 文が終わってから「アタリ!」「ハズレ」を true/false に基づいて 1 回だけ出力するようにすると、求める動作になります。

サンプルコードを以下に隠しておきます(マウスカーソルを上にかざすと表示されます)ので、必要に応じて参考にして下さい。

boolean flag = false;
for (int a : numbers) {
    if (a == input) {
        flag = true;
        break;
    }
}
if (flag) {
    System.out.println(“アタリ!”);
} else {
    System.out.println(“ハズレ”);
}

アルゴリズムについての整理

int型配列numbersにint型値inputが含まれていればアタリを表示し含まれていなければハズレを出力する。この要件を満たすような手続きの記述方法はいくつかある。
(紙面節約のためjavaらしくない{}の配置をしているがうまく読み替えてください)

プログラム1

プログラム1は、上記アルゴリズムを直接書き下す方法でありおそらく速度も速い。
下記の方法ではbreakを使っており、アタリを見つけ次第forを抜けるため効率的である。
このようにアルゴリズムを直接書き下すようなやり方を命令的プログラミングと表現することがある。

class Aaaa{
    public static void main (String[] args) {
        int[] numbers = {3,4,9};
        int input = new java.util.Scanner(System.in).nextInt();
        for(int i=0;i<numbers.length;i++){
            if(numbers[i]==input){System.out.println("アタリ!");break;}
            if(i==numbers.length-1){System.out.println("ハズレ!");}
}}}

上記のアルゴリズムでは拡張for文 つまりfor(int a:numbers)という記述を使っていない。
これはなぜか?配列の最後の要素において処理を分岐する必要があるからである。
(アタリが無かったということを記述する必要がある)
ある特定の要素のみ処理を変えるという記述が必要ならば拡張for文はうまくいかない。
参考までに下記URLを記載しておく。(イテレータという概念を用いて最後の要素だけ処理を変えるというテクであるが、素直にfor文を書いたほうがいいと思われる)
https://hacknote.jp/archives/20420/

プログラム2

プログラム1は動作は速いがいかにも不安が付きまとう。インデックスの指定が間違っているのではないか、バグが混入しているのではないか?
我々はもっと見通しのよい、バグのないことを確証できるようなプログラムを書きたいと思う。
本当はpythonやSQLでいうところのin演算子があればよいのだが、javaにはない。

Arrays.asList(numbers).contains(input)

本当は上記のように判定できたらいいのだが、javaはint型の配列(正確にはprimitive型の配列)をListにうまくキャストしてくれない。(上記の配列を要素として持つ長さ1のListになるため、この記述では期待する結果を得ることができない)
参考になるURLをもう一つ記述する。
https://stackoverflow.com/questions/1128723/how-can-i-test-if-an-array-contains-a-certain-value
この質問と回答は非常にレベルが高いが要約すると、

class Aaaa{
    public static void main (String[] args){
        int[] numbers = {3,4,9};
        int input = new java.util.Scanner(System.in).nextInt();
        if(java.util.stream.IntStream.of(numbers).anyMatch(a -> a == input)) 
            {System.out.println("アタリ");}
        else
            {System.out.println("ハズレ");}
}

と記述するのがいいと示唆している。特に重要なのがif文の中である。
まずはint型配列numbersをint型のストリームにキャストしている。ストリームは配列などを頭から順番に1つずつ要素を取り出していくようなものだとイメージしておけばよい。
a -> a==inputはいわゆるラムダ式と呼ばれているもので、これは入力はa 出力はa==inputというbool型数値となるような関数を短く書いているに過ぎない。aの具体的な値は3とか4とか9が順番に入っていくとイメージすればいい。
上記ラムダ式(関数)は入力3,4,9というストリームをFalse,False,Trueというストリームに置きかえる。
anyMatch関数はFalse,False,Trueという流れ(ストリーム)をTrueに置き換える。
anyMatchは例えばTrue,False,Falseという流れを受け取った場合、最初がTrueだと分かった時点で計算をbreakしてTrueを返す、そういう関数であるので効率はそれほど悪くない。
プログラム2のような書き方を宣言的なプログラムと呼ぶことがある。アルゴリズムの詳細(インデックスがどうとか、分岐がどうとか)をプログラマが指定することなくただnumbersの中にinputと==になるものがあれば”アタリ”、そうでないならば”ハズレ”と出力せよと書いている。

どちらがよいか

基本的にはプログラム2のような書き方を推奨する。ストリームAPIは汎用性が高いプログラムを短く記述でき細かい分岐の指定を回避することができるためである。ただプログラム1のような記述を知っておくことも重要である。

出典

Related Posts:

JavaFXで表に画像を表示できなくて困っています。 – java javafx exception
質問: 学校でソーシャルゲームを作っている最中、編成画面のために配列を解読して表を作成するプログラムを作ろうとした所、ResourceBundleがnullでセル内部に画像を表示できない状況です。 Cards.javaの最終的なコード: class csvData{ // 列数 static int NUMBER = 5+1+10+3+2+5+3+3;//chara static String charlist = csvlist_hen.setload("_chara.csv",NUMBER); static String wepidlist = csvlist_hen.setload("_wep.csv",13); static String abidlist = csvlist_hen.setload("_ability.csv",14); } class cmain{ private ...
leap_year.javaにコンパイルエラーが出る – java
質問: leap_year.java class leap_year{ int dim; int uruudosi(int yy); if((year % 4 == 0 && year ...
最高得点と最低得点を出したいのですが・・・ – java
質問: java内での入力 import java.io.*; class sample61{ public static void main(String args) throws IOException{ System.out.println("テストの受験者数を入力してください。"); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); ...
Javaについて – java
質問: AはBのオブジェクトを生成してBを返す Bはレコードを追加する Cは引数にBのオブジェクトを持ち追加したレコードによってファイルを作成しそのファイル名を返す AとBはできましたがBで作成したlistをどうやってCに渡すかがわかりません public class A{ public B create(){ B b = new B() ...
Aizu Onlineジャッジ 二つのサイコロの一致 – java
質問: Aizu online, Introduction to Programming 11-3のサイコロの一致を判定する問題をJavaで解いているのですが、テストケース(6/35)しか通らず、どこが間違っているのかわかりません。 どなたか間違いが見つかったら教えていただいてもいいでしょうか。 BufferedReader reader=new BufferedReader(new InputStreamReader(System.in)); String str; String dice; ...
変数の値が増えたか減ったかの判定方法 – javascript swift php
質問: Swiftで実装したいのですがロジックが応用できればどんな言語でも構いません。とある変数の値(数字)が動的に変わるのですが、その変数の値が増えたのか減ったのかで処理を分岐させたいと思っています。コードは下記のような感じです。 if(変数の値が増えた){ print("変数の値が増えた!") }esle if(いや、変数の値が減った){ print("変数の値が減った!") } 実装の方法が思いつきません。アドバイスいただければ幸いです 質問者: ryosuke-hujisawa 変更前の値と変更後の値を配列にとって配列の最初と最後を比較することで解決しました 出典
nullpointerexceptionについて – java processing leap-motion
質問: こんにちは、エラーが出て困ってます。ご教授ください。 import ddf.minim.*; //minimライブラリのインポート Minim minim; //Minim型変数であるminimの宣言 AudioPlayer player ; //サウンドデータ格納用の変数 int i; import com.onformative.leap.LeapMotionP5; import com.leapmotion.leap.Finger; AudioPlayer loopSound; float x,y; LeapMotionP5 leap; void setup(){ minim = ...
androidで写真撮影した画像を直接sqliteに書き込みたい – android java android-studio
質問: androidで写真撮影した画像を直接sqliteに保存したいのですが上手くできません。 写真の撮影で指定のフォルダーに写真保存できるのですがsqliteに写真データの保存ができなく困っています。 BitmapDB.java public class BitmapDB extends SQLiteOpenHelper { /** * 画像管理テーブル名 */ public static final String SAVE_PHOTO_TABLE = "save_photo"; /** * カラム名 画像ファイル名 */ public static final String COLUMN_FILE_NAME ...
Javaで値を繰り返し入力し合計値が100を超える、または、10回入力が行われた場合に入力を止めそれまでの値を出力するプログラム – java
質問: Java初心者です。 値を繰り返し入力し合計値が100を超える、または、10回入力が行われた場合に入力を止めそれまでの値を出力するプログラムを作成しています。 Eclipseでループ処理と配列を使って書いているんですが、whileで条件を指定したところ、 以下の警告が出てしまいます。 ・演算子 < は引数の型 Scanner, int で未定義です スコープの外で定義していると思うのですが、 エラーが出てしまう理由がよくわからないので、 解決策を教えてください。 お願いします。 int s = new int; int input = 0; ...
オプションメニューの内容を動的に変更する(Kotlin) – android java kotlin
質問: オプションメニューの内容を動的に変更したいのですが、MenuItemのインスタンス作成時にエラーが出ます。参考サイト var item = MenuItem() kotlinの場合、参考サイトと同じようにできるのでしょうか? こちらにも同じ質問をしていますTeratail 質問者: hai123 yukihane 正攻法としては、Kotlin文法を学びJavaコードと対応付けられるようにする、ということになると思いますが、マルチポスト先ではそのよう指向されているようなので別の邪道を。 KotlinでAndroid開発を行っているということはおそらくAndroid Studio上で開発していると思われますが、JavaからKotlinへの変換機能があります。 Javaコードが既に存在しているのであれば、その機能で自動変換してやればそれなりのKotlinコードが得られます。 今回の場合、適当にダミーのActivityクラスを新規作成し、そのファイルに該当メソッドをペーストした後、上記の機能を使用すると次のように変換されます。 override fun onPrepareOptionsMenu(menu: Menu): Boolean { super.onPrepareOptionsMenu(menu) // メニューアイテムを取得 ...
既存プログラム改定についての作業ノウハウ [クローズ済み] – java sql
質問: 業務プログラム開発に携わって5年以上、製造ラインで作業員として働いている状況です。 今の開発現場で2000年頃から保守され続けているプログラムの改定作業をやることが多くあり、経験も重なってきている状況です。 作業内容として、改定依頼(不具合事案から原因の修正)→(私)原因調査→修正という流れが主なのですが、原因調査を深く追えず、ダメ出しを頻繁に受けています。 長い年数やっても、こんな体たらくですが、自分で選んだ仕事、お客さんにご迷惑おかけしないよう努めていきたい一心ではあるのですが、うまくやれません。 ホウレンソウも下手なので、かなり注意を払っています。 指摘側からの言葉から察するに、自己注意力を問われている感じはします。 みなさん、どんな風に気を付けられていますか? 質問者: shinji tutinoco なぜ自分は原因調査を深く追えないのか、その理由を考えてみてはどうでしょうか。 恐らく、あなたは自分と向き合う時期に立たされているのではないかと思われます。 頑張っているはずなのに、うまくやれないという心理状態は 本当は心の奥ではやりたくないと思っていることが多いです。 人が何か行うとき、本来「必要だから行う」のであって 「行わなければならない」というものではありません。 もしあなたが「行わなければならない」という心理状態になっているのだとしたら 現在の自分の状況や立場、これからの自分について深く考察し 「必要だから行う」という思考に切り替えていく必要があります。 一人で考えて迷ったり悩んだりした場合には、できるだけ大きな書店に足を運び 目に止まった本をかたっぱしから読むことをおすすめします。 最後に、スタックオーバーフローでは、このような質問は少々不適切なので 右上の「ヘルプ」に使い方の詳細が掲載されていますので、いちど目を通しておくと良いでしょう! 出典
データベースでシングルクォーテーションを有効にするには? – java mysql
質問: 超初心者です。データベースに登録するのにシングルクオーテーションが入ってるとエラーが出ます。どうしたらシングルクォーテーションが有効にできますか? 質問者: user24415 sql = "SELECT * FROM tbl WHERE name = '" + param +"'"; こういうコードで、paramにシングルクオーテーションを含んだ文字列、例えば123'456が入っていると、生成されるSQLは SELECT * FROM tble WHERE name = ...
error: No resource identifier found for attribute ‘latout_height’ in package ‘android’ の意味を教えてください – android java
質問: error: No resource identifier found for attribute 'latout_height' in package 'android' javaを利用していたところこのようなエラーが発生しました。解決方法を教えていだだけますか。 質問者: user5871 スペルミスが原因です。 latout_heightではなくlayout_heightとすればエラーがなくなりませんか? エラーメッセージを読んでも原因が分からないときはそのままエラーメッセージでググって、そのエラーメッセージがどういう状況のときに発生するかを調べるのも直接的な解決にはならなくても1つの方法だと思います。そのうちに発生パターンが分かってくると自分で間違いに気付けるようになるかもしれません。 ...
public object の使い方 – android java android-studio
質問: この質問は、次と完全に重複しています: is not public in ...
R.javaの中身 – android java eclipse
質問: このプログラムでのエラーを治していただける方、お願いします。 package a.a; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; public class A extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { ...

You Might Also Like

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です