আমি কীভাবে জাভা পদ্ধতিতে অকেজো রিটার্ন এড়াব?


115

আমার এমন পরিস্থিতি রয়েছে যেখানে returnদুটি forলুপে নেস্টেট করা বিবৃতিটি সর্বদা তাত্ত্বিকভাবে পৌঁছে যাবে।

সংকলকটি একমত নয় এবং লুপের returnবাইরে একটি বিবৃতি প্রয়োজন for। আমি আমার বর্তমান বোধগম্যতার বাইরে এই পদ্ধতিটি অনুকূলকরণের জন্য একটি দুর্দান্ত উপায় জানতে চাই এবং আমার বিরতির বাস্তবায়নের কোনওটিই কাজ করছে বলে মনে হয় না।

সংযুক্তি একটি অ্যাসাইনমেন্ট থেকে একটি পদ্ধতি যা এলোমেলো পূর্ণসংখ্যার উত্পন্ন করে এবং দ্বিতীয় র্যান্ডম পূর্ণসংখ্যার সন্ধান না হওয়া অবধি চক্রের পুনরাবৃত্তিগুলি প্রদান করে, কোনও পদ্ধতিটি প্যারামিটার হিসাবে পদ্ধতিতে পাস করা একটি পরিসরের মধ্যে উত্পন্ন হয়।

private static int oneRun(int range) {
    int[] rInt = new int[range+1]; // Stores the past sequence of ints.
    rInt[0] = generator.nextInt(range); // Inital random number.

    for (int count = 1; count <= range; count++) { // Run until return.
        rInt[count] = generator.nextInt(range); // Add randint to current iteration.
        for (int i = 0; i < count; i++) { // Check for past occurence and return if found.
            if (rInt[i] == rInt[count]) {
                return count;
            }
        }
    }
    return 0; // Never reached
}

9
শেষ আইটেমটি যদি কখনও পৌঁছায় না, তবে আপনি while(true)কোনও সূচকযুক্ত লুপের পরিবর্তে একটি ব্যবহার করতে পারেন । এটি সংকলককে বলে যে লুপটি আর ফিরে আসবে না।
বোরিস স্পাইডার

101
0 (বা 1 এর চেয়ে কম অন্য কোনও সংখ্যার) সাথে ফাংশনটি কল করুন ( oneRun(0)এবং আপনি দেখতে পাচ্ছেন যে আপনি দ্রুত আপনার অ্যাক্সেসযোগ্যতে পৌঁছেছেনreturn
এমসিএফিডার

55
সরবরাহ পরিসীমা নেতিবাচক হলে প্রত্যাবর্তন পৌঁছে যায়। আপনার কাছে ইনপুট ব্যাপ্তির জন্য 0 বৈধতা আছে, সুতরাং আপনি বর্তমানে এটি অন্য কোনও উপায়ে ধরছেন না।
আশাকরি

4
নিঃসন্দেহে হেল্পফুল এটি অবশ্যই আসল উত্তর। এটি মোটেও অকেজো রিটার্ন নয়!
মিস্টার লিস্টার

4
@ আশাবাদী না, কারণ nextIntব্যতিক্রম ছুঁড়ে ফেলা হয়েছে range < 0কেবল যেখানে প্রত্যাবর্তন পৌঁছেছে তা হলrange == 0
njzk2

উত্তর:


343

সংকলকের হিউরিস্টিকস আপনাকে শেষটি বাদ দিতে দেয় না return। আপনি যদি নিশ্চিত হন যে এটি কখনই পৌঁছবে throwনা, তবে পরিস্থিতি স্পষ্ট করার জন্য আমি এটি দিয়ে প্রতিস্থাপন করব ।

private static int oneRun(int range) {
    int[] rInt = new int[range+1]; // Stores the past sequence of ints.
    rInt[0] = generator.nextInt(range); // Inital random number.

    for (int count = 1; count <= range; count++) {
        ...
    }

    throw new AssertionError("unreachable code reached");
}

135
কেবল পঠনযোগ্যতা নয়, আপনার কোডটিতে কোনও সমস্যা আছে কিনা তা নিশ্চিত করে তোলে। এটি জেনারেটরের একটি বাগ থাকতে পারে এটি পুরোপুরি প্রশংসনীয়।
জলি জোকার

6
আপনি যদি নিখুঁতভাবে নিশ্চিত হন যে আপনার কোডটি কখনই "অ্যাক্সেসযোগ্য কোড" এ না পারা যায় তবে উত্পন্ন হতে পারে এমন সমস্ত প্রান্তের ক্ষেত্রে কিছু ইউনিট পরীক্ষা তৈরি করুন (পরিসীমা 0, পরিসীমা -1, সর্বাধিক ন্যূনতম / সর্বোচ্চ) int এটি এখন একটি ব্যক্তিগত পদ্ধতি হতে পারে তবে পরবর্তী বিকাশকারী এটি সেভাবে রাখবেন না। আপনি কীভাবে অপ্রত্যাশিত মানগুলি পরিচালনা করেন (একটি ব্যতিক্রম ছুঁড়ে দেওয়া, ত্রুটির মান ফিরিয়ে দেওয়া, কিছুই না করা) আপনি কীভাবে পদ্ধতিটি ব্যবহার করতে চলেছেন তার উপর নির্ভর করে। আমার অভিজ্ঞতায় আপনি সাধারণত একটি ত্রুটি লগইন করে ফিরে আসতে চান।
রিক রাইকার

22
হতে পারে এটি হওয়া উচিতthrow new AssertionError("\"unreachable\" code reached");
বোহেমিয়ান

8
আমি আমার প্রোডাকশন প্রোগ্রামে আমার উত্তরটি যা লিখেছিলাম ঠিক তা লিখতে চাই।
জন কুগেলম্যান

1
প্রদত্ত উদাহরণের সাথে মোকাবিলা করার আরও ভাল উপায় রয়েছে যা কেবল throwকখনও পৌঁছাতে পারে না add বেশিরভাগ ক্ষেত্রে লোকেরা অন্তর্নিহিত সমস্যাটি সম্পর্কে খুব বেশি চিন্তা না করে কেবল "দ্রুত তাদের সকলের জন্য একটি সমাধান" প্রয়োগ করতে চায়। প্রোগ্রামিং কেবল কোডিংয়ের চেয়ে অনেক বেশি। বিশেষত এটি যখন অ্যালগরিদমের কথা আসে। যদি আপনি (সাবধানে) প্রদত্ত সমস্যাটি পরিদর্শন করেন, আপনি বুঝতে পারবেন যে আপনি বাইরের forলুপের শেষ পুনরাবৃত্তিটি নির্ধারণ করতে পারেন এবং অতএব "অকেজো" রিটার্নকে কোনও দরকারী দ্বারা প্রতিস্থাপন করতে পারেন ( এই উত্তরটি দেখুন )।
a_guest 14

36

হিসাবে @BoristheSpider নির্দিষ্ট আপনি কি নিশ্চিতরূপে দ্বিতীয় করতে পারেন returnবিবৃতি শব্দার্থিক ভাবে পৌছানো যাচ্ছে না:

private static int oneRun(int range) {
    int[] rInt = new int[range+1]; // Stores the past sequence of ints.
    int count = 0;

    while (true) {
        rInt[count] = generator.nextInt(range); // Add randint to current iteration.
        for (int i = 0; i < count; i++) { // Check for past occurence and return if found.
            if (rInt[i] == rInt[count]) {
                return count;
            }
        }
        count++;
    }
}

সংকলন এবং জরিমানা রান। এবং যদি আপনি কখনও পেয়ে থাকেন তবে আপনি ArrayIndexOutOfBoundsExceptionজানবেন বাস্তবায়ন শব্দার্থগতভাবে ভুল ছিল, স্পষ্টতই কিছু ছুঁড়ে না ফেলে।


1
ঠিক: শর্তটি আসলে লুপটি নিয়ন্ত্রণ করতে ব্যবহৃত হয় না, সুতরাং এটি থাকা উচিত নয়। যাইহোক, আমি for(int count = 0; true; count++)পরিবর্তে এটি লিখতে হবে।
cmaster - পুনর্বহাল মনিকা

3
@cmaster: আপনি বাদ পারেন true:for(int count = 0; ; count++) …
হোলগার

@ হোলগার আহ। আমি এটি সম্পর্কে নিশ্চিত ছিলাম না কারণ এটি জাভা সম্পর্কে, এবং আমি বহু বছর ধরে সেই ভাষাটি স্পর্শ করি নি যেহেতু আমি আরও অনেক বেশি সি / সি ++ তে আছি। সুতরাং, যখন আমি এর ব্যবহার দেখেছি while(true), আমি ভেবেছিলাম যে সম্ভবত জাভা এই বিষয়ে কিছুটা কঠোর। true
চিন্তার দরকার নেই জেনে ভাল লাগলো

3
আমি "জন্য" স্যুইচ না করতে পছন্দ করব। একটি "যখন-সত্য" এটি একটি স্পষ্ট পতাকা যা এই ব্লকটি নিঃশর্তভাবে লুপ করার প্রত্যাশা করে, যতক্ষণ না অভ্যন্তর কোনও কিছু ভেঙে যায়। বাদ দেওয়া শর্তযুক্ত একটি "ফর" স্পষ্টভাবে যোগাযোগ করে না; এটি আরও সহজে উপেক্ষা করা যেতে পারে।
Corrodias

1
@ l0b0 সতর্কবাণী কোড মানের সাথে সম্পর্কিত বিবেচনা করে কোড রিভিউয়ের জন্য পুরো প্রশ্নটি সম্ভবত ভাল।
সুলতান

18

যেহেতু আপনি দুটি forলুপ ভাঙার বিষয়ে জিজ্ঞাসা করেছেন , আপনি এটি করতে একটি লেবেল ব্যবহার করতে পারেন (নীচের উদাহরণটি দেখুন):

private static int oneRun(int range) {
    int returnValue=-1;

    int[] rInt = new int[range+1]; // Stores the past sequence of ints.
    rInt[0] = generator.nextInt(range); // Inital random number.

    OUTER: for (int count = 1; count <= range; count++) { // Run until return.
        rInt[count] = generator.nextInt(range); // Add randint to current iteration.   
        for (int i = 0; i < count; i++) { // Check for past occurence and return if found.
            if (rInt[i] == rInt[count]) {
                returnValue = count;
                break OUTER;
            }
        }
    }
    return returnValue;
}

এটি কি সংকলন returnValueকরতে ব্যর্থ হবে কারণ অবিচ্ছিন্নভাবে ব্যবহার করা যেতে পারে?
পিটিএস

1
খুব সম্ভবত। মূল পোস্টার এ সম্পর্কে জিজ্ঞাসা করেছিল, পোস্টটির উদ্দেশ্যটি উভয় লুপগুলি কীভাবে ভেঙে যায় তা দেখানো ছিল। ওপি নিশ্চিত ছিল যে মৃত্যুদন্ড কার্যকর করার পদ্ধতিটি কখনই শেষ হবে না, সুতরাং আপনি যে বিষয়টি নিয়ে এসেছেন তা রিটার্নভ্যালুটি যে কোনও মান হিসাবে ঘোষণা করার পরে শুরু করে ঠিক করা যেতে পারে।
ডেভিড চৌএলর

4
লেবেলগুলি এমন ধরণের জিনিসগুলি কোনও উপায়ে আপনি এড়ানো ভাল নয়?
সার্ভারফ্রোগ

2
আমি বিশ্বাস করি আপনি গোটোসের কথা ভাবছেন।
ডেভিড চৌহেলার

4
একটি উচ্চ (-শ) স্তরের প্রোগ্রামিং ভাষাতে লেবেল। একেবারে বর্বর ...
xDaiizu

13

যদিও একটি জোর দেওয়া ভাল দ্রুত সমাধান is সাধারণভাবে এই ধরণের সমস্যার অর্থ হল আপনার কোডটি খুব জটিল। আমি যখন আপনার কোডটি দেখছি, এটি স্পষ্টতই আপনি পূর্ববর্তী সংখ্যাগুলি ধরে রাখতে কোনও অ্যারে চান না। আপনি একটি চান Set:

Set<Integer> previous = new HashSet<Integer>();

int randomInt = generator.nextInt(range);
previous.add(randomInt);

for (int count = 1; count <= range; count++) {
    randomInt = generator.nextInt(range);
    if (previous.contains(randomInt)) {
       break;
    }

    previous.add(randomInt);
}

return previous.size();

এখন নোট করুন যে আমরা ফিরে যাচ্ছি তা আসলে সেটটির আকার। কোড জটিলতা চতুর্ভুজ থেকে লিনিয়ারে হ্রাস পেয়েছে এবং এটি অবিলম্বে আরও পঠনযোগ্য।

এখন আমরা বুঝতে পারি যে আমাদের এমনকি সেই countসূচকের প্রয়োজন নেই :

Set<Integer> previous = new HashSet<Integer>();

int randomInt = generator.nextInt(range);

while (!previous.contains(randomInt)) {          
    previous.add(randomInt);      
    randomInt = generator.nextInt(range);
}

return previous.size();

8

আপনার রিটার্নের মান বাইরের লুপের ভেরিয়েবলের উপর ভিত্তি করে আপনি কেবলমাত্র বাহিরের লুপের অবস্থার পরিবর্তন করতে পারেন count < rangeএবং তারপরে ফাংশনটির শেষে এই শেষ মানটি (যা আপনি কেবল বাদ দিয়েছেন) ফিরিয়ে দিতে পারেন:

private static int oneRun(int range) {
    ...

    for (int count = 1; count < range; count++) {
        ...
    }
    return range;
}

এইভাবে আপনার এমন কোড প্রবর্তনের দরকার নেই যা কখনই পৌঁছাতে পারে না।


তবে ম্যাচটি পাওয়া গেলে লুপের দুটি স্তর থেকে বেরিয়ে যাওয়ার দরকার নেই? আমি বিবৃতি দেওয়ার জন্য একটিতে হ্রাস করার উপায় দেখছি না, একটি নতুন এলোমেলো সংখ্যা তৈরি করা দরকার এবং অন্যটি উত্পন্ন হওয়ার আগে এর সাথে তুলনা করা দরকার।
অলিভার বেনিং

আপনি এখনও দুটি লুপের জন্য নেস্টেড রেখে গেছেন (আমি কেবল দ্বিতীয়টি বাদ দিয়েছি ...) তবে বাইরের লুপটি এর শেষ পুনরাবৃত্তির দ্বারা হ্রাস পেয়েছে। এই শেষ পুনরাবৃত্তির সাথে সম্পর্কিত কেসটি খুব শেষ রিটার্নের বিবৃতি দ্বারা পৃথকভাবে পরিচালনা করা হয়। যদিও এটি আপনার উদাহরণের জন্য একটি মার্জিত সমাধান তবে এমন দৃশ্যগুলি রয়েছে যা এই পদ্ধতির পড়া আরও কঠিন হয়ে পড়ে; উদাহরণস্বরূপ যদি রিটার্ন মানটি তারপরে অভ্যন্তরীণ লুপের উপর নির্ভর করে - শেষে একক রিটার্নের স্টেটমেন্টের পরিবর্তে - আপনাকে একটি অতিরিক্ত লুপ (বাইরের লুপের শেষ পুনরাবৃত্তির জন্য অভ্যন্তরীণ লুপকে উপস্থাপন করে) রেখে দেওয়া হবে।
a_guest

5

একটি টেম্প ভেরিয়েবল ব্যবহার করুন, উদাহরণস্বরূপ "ফলাফল" এবং অভ্যন্তরীণ রিটার্নটি সরিয়ে দিন। সঠিক অবস্থার সাথে লুপের জন্য কিছুক্ষণ পরিবর্তন করুন। আমার কাছে ফাংশনের শেষ বক্তব্য হিসাবে কেবলমাত্র একটি রিটার্ন পাওয়া সবসময়ই মার্জিত।


ভাল, দেখতে খুব ভিতরের মতো যদি শর্তের পরে বাইরের হতে পারে। মনে রাখবেন যে এর জন্য সর্বদা একটি সমতুল্য (এবং আরও মার্জিত যেহেতু আপনি সবসময় সমস্ত পুনরাবৃত্তির মধ্য দিয়ে যাওয়ার পরিকল্পনা করছেন না) equivalent লুপগুলির জন্য দু'টি নেস্টেড নিশ্চিতভাবে সরল করা যেতে পারে। সমস্ত কোড "খুব জটিল" গন্ধযুক্ত।
ডেভিড

@ সলোমনফের সেক্রেট আপনার বক্তব্য অযৌক্তিক। এটি বোঝায় যে আমাদের "সাধারণভাবে" দুটি বা ততোধিক রিটার্ন স্টেটমেন্টের লক্ষ্য করা উচিত। মজাদার.
ডেভিড

@ সলোমনফসের সেক্রেট এটি পছন্দসই প্রোগ্রামিং শৈলীর বিষয়, এবং গত সপ্তাহে লম্বা এই সপ্তাহে যা শীতল তা নির্বিশেষে, কেবলমাত্র একটি বহির্গমন পয়েন্ট থাকার পক্ষে সঠিক পদ্ধতি রয়েছে এবং পদ্ধতির শেষে (কেবল একটি লুপের সাথে ভাবুন) অনেকে এর মধ্যে return resultছড়িয়ে পড়ে এবং তারপরে resultফিরে আসার আগে এখন আরও একটি চেক করতে চান তা ভাবেন , এবং এটি কেবল উদাহরণ)। কনসও থাকতে পারে তবে "সাধারণভাবে, কেবলমাত্র একমাত্র ফেরত পাওয়ার ভাল কারণ নেই" জল ধরে না as
সান্টিবাইলર્સ

@ ডেভিড আমাকে পুনঃপ্রকাশ করতে দিন: কেবলমাত্র একটি করে ফেরার কোনও সাধারণ কারণ নেই। বিশেষ ক্ষেত্রে কারণগুলি হতে পারে তবে সাধারণত এটি সবচেয়ে খারাপ সময়ে কার্গো কাল্ট।
মনিকা পুনরায়

1
কোডটি আরও পাঠযোগ্য। যদি আপনার মাথায় আপনি বলে থাকেন যে "এটি যদি এটি হয় তবে যা আমরা পেয়েছি তা ফিরিয়ে দিন; অন্যথায় চালিয়ে যান; যদি আমরা কিছু না পাই তবে এই অন্য মানটি ফেরত দিন"। তারপরে আপনার কোডের দুটি রিটার্ন মান থাকতে হবে। এটিকে পরবর্তী বিকাশকারীকে আরও তত্ক্ষণাত বোধগম্য করে তোলে এমন কোড করুন। সংকলকটিতে জাভা পদ্ধতি থেকে কেবল একটি রিটার্ন পয়েন্ট রয়েছে যদিও আমাদের চোখে এটি দু'র মতো লাগে।
রিক রাইকার

3

হতে পারে এটি একটি ইঙ্গিত যা আপনার কোডটি পুনরায় লিখতে হবে। উদাহরণ স্বরূপ:

  1. পূর্ণসংখ্যার 0 .. রেঞ্জ -1 এর অ্যারে তৈরি করুন। সমস্ত মান 0 তে সেট করুন।
  2. একটি লুপ সঞ্চালন। লুপে, একটি এলোমেলো সংখ্যা তৈরি করুন। আপনার তালিকায়, সেই সূচীতে দেখুন, মানটি 1 হয় কিনা তা দেখতে লুপটি ভেঙে দিন। অন্যথায়, সেই সূচকে মান 1 এ সেট করুন
  3. তালিকায় 1 টি সংখ্যা গণনা করুন এবং সেই মানটি ফিরিয়ে দিন।

3

যে পদ্ধতিগুলির একটি রিটার্ন স্টেটমেন্ট থাকে এবং সেগুলির ভিতরে একটি লুপ / ​​লুপ থাকে সেগুলির জন্য সর্বদা লুপের বাইরে ফিরতি বিবৃতি প্রয়োজন statement এমনকি লুপের বাইরের এই বিবৃতিটি কখনও পৌঁছায় না। এই জাতীয় ক্ষেত্রে, অপ্রয়োজনীয় রিটার্নের বিবৃতি এড়াতে, আপনি পদ্ধতিটির শুরুতে সম্পর্কিত লুপের (গুলি) এর আগে ও বাইরে, সম্পর্কিত প্রকারের আপনার ক্ষেত্রে একটি পূর্ণসংখ্যার সংজ্ঞা দিতে পারেন। লুপের ভিতরে কাঙ্ক্ষিত ফলাফল পৌঁছে গেলে আপনি এই প্রাক-সংজ্ঞায়িত ভেরিয়েবলের জন্য সংশ্লিষ্ট মানটিকে স্বীকৃতি দিতে পারেন এবং এটি লুপের বাইরে রিটার্ন স্টেটমেন্টের জন্য ব্যবহার করতে পারেন।

যেহেতু আপনি চান আপনার পদ্ধতিটি প্রথম ফলাফলটি ফিরে আসে যখন rInt [i] rInt [গণনা] এর সমান হয়, কেবলমাত্র উপরে বর্ণিত ভেরিয়েবল প্রয়োগ করা যথেষ্ট নয় কারণ rInt [i] rInt [গণনা] এর সমান হলে পদ্ধতিটি শেষ ফলাফলটি ফিরে আসবে। একটি বিকল্প হ'ল দুটি "ব্রেক স্টেটমেন্ট" প্রয়োগ করা যা আমাদের যখন পছন্দসই ফলাফল দেয় তখন ডাকা হয়। সুতরাং, পদ্ধতিটি এরকম কিছু দেখবে:

private static int oneRun(int range) {

        int finalResult = 0; // the above-mentioned variable
        int[] rInt = new int[range + 1];
        rInt[0] = generator.nextInt(range);

        for (int count = 1; count <= range; count++) {
            rInt[count] = generator.nextInt(range);
            for (int i = 0; i < count; i++) {
                if (rInt[i] == rInt[count]) {
                    finalResult = count;
                    break; // this breaks the inside loop
                }
            }
            if (finalResult == count) {
                break; // this breaks the outside loop
            }
        }
        return finalResult;
    }

2

আমি সম্মত হলাম যে যেখানে অপ্রাপ্য বক্তব্য আসে সেখানে একটি ব্যতিক্রম ছুঁড়ে ফেলা উচিত। কেবল একই পদ্ধতিটি আরও পঠনযোগ্য উপায়ে এটি কীভাবে করতে পারে তা কেবলমাত্র দেখতে চেয়েছিলেন (জাভা 8 টি স্ট্রিম প্রয়োজনীয়)।

private static int oneRun(int range) {
    int[] rInt = new int[range + 1];
    return IntStream
        .rangeClosed(0, range)
        .peek(i -> rInt[i] = generator.nextInt(range))
        .filter(i -> IntStream.range(0, i).anyMatch(j -> rInt[i] == rInt[j]))
        .findFirst()
        .orElseThrow(() -> new RuntimeException("Shouldn't be reached!"));
}

-1
private static int oneRun(int range) {
    int result = -1; // use this to store your result
    int[] rInt = new int[range+1]; // Stores the past sequence of ints.
    rInt[0] = generator.nextInt(range); // Inital random number.

    for (int count = 1; count <= range && result == -1; count++) { // Run until result found.
        rInt[count] = generator.nextInt(range); // Add randint to current iteration.   
        for (int i = 0; i < count && result == -1; i++) { // Check for past occurence and leave after result found.
            if (rInt[i] == rInt[count]) {
                result = count;
            }
        }
    }
    return result; // return your result
}

কোড অদক্ষ এছাড়াও যেহেতু এক কি করতে হবে অনেক এর result == -1চেক যা দিয়ে বাদ দেওয়া যেতে পারে returnভিতরে লুপ ...
উইলেম ভ্যান Onsem
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.