জাভা 8 কোনও মান বা ফাংশনটির পুনরাবৃত্তি করার ভাল উপায় সরবরাহ করে?


118

অন্যান্য অনেক ভাষায়, যেমন। হাস্কেল, কোনও মান পুনরাবৃত্তি করা বা একাধিকবার ফাংশন করা সহজ, যেমন। মান 1 এর 8 কপির একটি তালিকা পেতে:

take 8 (repeat 1)

তবে জাভা 8-তে আমি এটি এখনও পাইনি Java

অথবা বিকল্পভাবে এর মতো পরিসরের সমতুল্য কিছু

[1..8]

এটি জাভা মত একটি ভার্বোস বিবৃতি জন্য একটি সুস্পষ্ট প্রতিস্থাপন বলে মনে হচ্ছে

for (int i = 1; i <= 8; i++) {
    System.out.println(i);
}

মত কিছু আছে

Range.from(1, 8).forEach(i -> System.out.println(i))

যদিও এই নির্দিষ্ট উদাহরণটি আসলে আরও সংক্ষিপ্ত দেখাচ্ছে না ... তবে আশা করি এটি আরও পাঠযোগ্য।


2
আপনি কি স্ট্রিমস এপিআই অধ্যয়ন করেছেন ? যতদূর জেডিকে সম্পর্কিত এটি আপনার সেরা বাজি হওয়া উচিত। এটি একটি পরিসীমা ফাংশন পেয়েছে , এটাই আমি এখনও খুঁজে পেয়েছি।
মার্কো টপলনিক

1
@ মারকোটোপলনিক স্ট্রিমস ক্লাসটি সরানো হয়েছে (আরও স্পষ্টভাবে এটি অন্যান্য কয়েকটি শ্রেণীর মধ্যে বিভক্ত হয়ে গেছে এবং কিছু পদ্ধতি সম্পূর্ণ অপসারণ করা হয়েছে)।
Assylias

3
আপনি লুপ ভার্বোস জন্য একটি কল! কোবোলের দিনগুলিতে আপনি খুব ভাল ছিলেন না। এটি আরোহণের সংখ্যা প্রদর্শন করতে কোবলে 10 টিরও বেশি ঘোষণামূলক বিবৃতি নিয়েছিল। তরুণরা আজকাল তাদের কতটা ভাল তা প্রশংসা করে না।
গিলবার্ট লে ব্ল্যাঙ্ক

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

2
@ গিলবার্টলেব্ল্যাঙ্ক এবং আমাদের বরফে খালি পায়ে কোড দিতে হয়েছিল।
দাউদ ইবনে কেরেম

উত্তর:


155

এই নির্দিষ্ট উদাহরণের জন্য, আপনি এটি করতে পারেন:

IntStream.rangeClosed(1, 8)
         .forEach(System.out::println);

আপনার যদি 1 থেকে আলাদা পদক্ষেপের প্রয়োজন হয় তবে আপনি একটি ম্যাপিং ফাংশন ব্যবহার করতে পারেন, উদাহরণস্বরূপ, 2 পদক্ষেপের জন্য:

IntStream.rangeClosed(1, 8)
         .map(i -> 2 * i - 1)
         .forEach(System.out::println);

অথবা একটি কাস্টম পুনরাবৃত্তি তৈরি করুন এবং পুনরাবৃত্তির আকার সীমাবদ্ধ করুন:

IntStream.iterate(1, i -> i + 2)
         .limit(8)
         .forEach(System.out::println);

4
ক্লোজারগুলি জাভা কোডটিকে পুরোপুরি রূপান্তর করবে, আরও ভাল। সেদিনের অপেক্ষায় ...
মার্কো টপলনিক

1
@ জওয়ান্টিং এটি সত্যই নির্ভর করে - সাধারণত জিইউআই স্টাফ (সুইং বা জাভাএফএক্স) দিয়ে, যা বেনাম শ্রেণীর কারণে প্রচুর বয়লার প্লেট সরিয়ে দেয় ।
assylias

8
@ জেভেন্টিং এফপিতে অভিজ্ঞতা সম্পন্ন যে কাউকে, উচ্চতর অর্ডার ফাংশনগুলির চারপাশে ঘুরানো কোডটি খাঁটি জয়। যে অভিজ্ঞতা ছাড়া যে কারও কাছে, আপনার দক্ষতা আপগ্রেড করার সময় --- বা ঝুঁকি ধুলায় ফেলে যাওয়ার সময়।
মার্কো টপলনিক

2
@MarkoTopolnik আপনি javadoc সামান্য নতুন সংস্করণ ব্যবহার করতে চাইতে পারেন (যদি আপনি 78 গড়ে তুলতে প্রতি নির্দেশ করা হয়, সর্বশেষ বিল্ড 105 হল: download.java.net/lambda/b105/docs/api/java/util/stream/... )
মার্ক রোটভিল

1
@ গ্রেমেমসস আপনি এখনও একই প্যাটার্নটি ব্যবহার করতে পারেন ( IntStream.rangeClosed(1, 8).forEach(i -> methodNoArgs());) তবে এটি আইএমওকে বিভ্রান্ত করে এবং সেই ক্ষেত্রে একটি লুপ ইঙ্গিতপ্রাপ্ত বলে মনে হয়।
Assylias

65

আমি অন্য দিনটি চালিয়ে গিয়েছিলাম এমন আরও একটি কৌশল এখানে রয়েছে:

Collections.nCopies(8, 1)
           .stream()
           .forEach(i -> System.out.println(i));

Collections.nCopiesকলের জন্য একটি সৃষ্টি Listধারণকারী nযাই হোক না কেন মান প্রদান কপি। এক্ষেত্রে এটি বাক্সযুক্ত Integerমান ১। অবশ্যই এটি nউপাদানগুলির সাথে তালিকাগুলি তৈরি করে না ; এটি একটি "ভার্চুয়ালাইজড" তালিকা তৈরি করে যা কেবলমাত্র মান এবং দৈর্ঘ্য ধারণ করে এবং getসীমার মধ্যে যে কোনও কল কেবল মানটি দেয়। nCopiesপদ্ধতি হয়েছে প্রায় যেহেতু সংগ্রহগুলি ফ্রেমওয়ার্ক JDK 1.2 উপায় ফিরে চালু করা হয়। অবশ্যই, জাভা এসই 8 এ এর ​​ফলাফল থেকে একটি স্ট্রিম তৈরি করার ক্ষমতা যুক্ত করা হয়েছিল।

বড় চুক্তি, একই সংখ্যক লাইনের একই জিনিসটি করার আরেকটি উপায়।

তবে এই কৌশলটি দ্রুত IntStream.generateএবং IntStream.iterateপদ্ধতির চেয়ে দ্রুত এবং আশ্চর্যজনকভাবে এটি IntStream.rangeপদ্ধতির চেয়েও দ্রুত than

কারণ iterateএবং generateফলাফল সম্ভবত খুব অবাক হয় না। স্ট্রিমস ফ্রেমওয়ার্ক (প্রকৃতপক্ষে, এই স্ট্রিমগুলির জন্য স্প্লিটেটরগুলি) এই ধারণার উপর ভিত্তি করে তৈরি করা হয়েছে যে ল্যাম্বডাস প্রতিটিবারই সম্ভাব্যভাবে বিভিন্ন মান তৈরি করবে এবং তারা একটি সীমাহীন ফলাফল তৈরি করবে। এটি সমান্তরাল বিভাজন বিশেষ করে কঠিন করে তোলে। iterateপদ্ধতি কারণ প্রতিটি কলের আগের ফল প্রয়োজন এই ক্ষেত্রে জন্য সমস্যাযুক্ত। সুতরাং স্ট্রিমগুলি বারবার ধ্রুবক তৈরির জন্য খুব ভাল করে না generateএবং ব্যবহার করে iterateনা।

অপেক্ষাকৃত দুর্বল অভিনয় rangeবিস্ময়কর। এটিও ভার্চুয়ালাইজড, সুতরাং উপাদানগুলি মেমরির মধ্যে আসলে বিদ্যমান থাকে না এবং আকারটি সামনে জানা যায়। এটি দ্রুত এবং সহজেই সমান্তরাল স্প্লিট্রেটারের তৈরি করা উচিত। তবে এটি আশ্চর্যজনকভাবে খুব ভাল করেনি। সম্ভবত কারণটি হ'ল rangeপরিসরের প্রতিটি উপাদানটির জন্য একটি মান গণনা করতে হবে এবং তারপরে একটি ফাংশন কল করতে হবে। তবে এই ফাংশনটি কেবল তার ইনপুটটিকে উপেক্ষা করে একটি ধ্রুবককে ফিরিয়ে দেয়, তাই আমি আশ্চর্য হয়েছি যে এটি ইনলাইনড এবং হত্যা করা হয়নি।

Collections.nCopiesকৌশল যেহেতু কোন আদিম বিশেষায়িত হয়, যাতে মান হ্যান্ডেল করার জন্য আনবক্সিং / বক্সিং কি আছে List। যেহেতু প্রতিবার মান একই হয় তাই এটি মূলত একবারে বক্স করা হয় এবং সেই বাক্সটি সমস্ত nঅনুলিপি দ্বারা ভাগ করা হয় । আমি সন্দেহ করি বক্সিং / আনবক্সিং উচ্চতর অনুকূলিত, এমনকি স্বতঃস্ফূর্ত এবং এটি ভালভাবে ইনলাইন করা যেতে পারে।

কোডটি এখানে:

    public static final int LIMIT = 500_000_000;
    public static final long VALUE = 3L;

    public long range() {
        return
            LongStream.range(0, LIMIT)
                .parallel()
                .map(i -> VALUE)
                .map(i -> i % 73 % 13)
                .sum();
}

    public long ncopies() {
        return
            Collections.nCopies(LIMIT, VALUE)
                .parallelStream()
                .mapToLong(i -> i)
                .map(i -> i % 73 % 13)
                .sum();
}

এবং এখানে জেএমএইচ ফলাফল রয়েছে: (2.8GHz কোর 2 ডুও)

Benchmark                    Mode   Samples         Mean   Mean error    Units
c.s.q.SO18532488.ncopies    thrpt         5        7.547        2.904    ops/s
c.s.q.SO18532488.range      thrpt         5        0.317        0.064    ops/s

এনসিপিগুলি সংস্করণে যথেষ্ট পরিমাণে বৈকল্পিক রয়েছে তবে সামগ্রিকভাবে এটি পরিসীমা সংস্করণের তুলনায় আরামদায়কভাবে 20x দ্রুত বলে মনে হচ্ছে। (যদিও আমি বিশ্বাস করতে বেশ আগ্রহী যে আমি কিছু ভুল করেছি।)

nCopiesকৌশলটি কতটা ভাল কাজ করে তা নিয়ে আমি অবাক । অভ্যন্তরীণভাবে এটি খুব বেশি বিশেষ করে না, ভার্চুয়ালাইজড তালিকার প্রবাহটি কেবল ব্যবহার করে প্রয়োগ করা হচ্ছে IntStream.range! আমি প্রত্যাশা করেছি যে এটি দ্রুত যাওয়ার জন্য একটি বিশেষায়িত স্প্লিটেটর তৈরি করা প্রয়োজন, তবে এটি ইতিমধ্যে বেশ ভাল বলে মনে হচ্ছে।


6
কম পাকা বিকাশকারীরা বিভ্রান্ত হতে পারে বা সমস্যার মধ্যে পড়তে পারে যখন তারা জানতে পারে যে nCopiesআসলে কিছুই অনুলিপি করে না এবং "অনুলিপিগুলি" সমস্ত একক বস্তুটির দিকে নির্দেশ করে। যদি সেই বস্তুটি অপরিবর্তনীয় হয় তবে এটি সর্বদা নিরাপদ , যেমন এই উদাহরণে বক্সযুক্ত আদিম। আপনি আপনার "একবারে বাক্সযুক্ত" বিবৃতিতে এটির ইঙ্গিত দিয়েছেন, তবে স্পষ্টতই এখানে সতর্কতার সাথে ডেকে আনা ভালো লাগবে কারণ আচরণটি অটো-বক্সিং সম্পর্কিত নির্দিষ্ট নয়।
উইলিয়াম দাম

1
সুতরাং যে বোঝায় যে LongStream.rangeতুলনায় উল্লেখযোগ্য ধীর IntStream.range? সুতরাং এটি খুব ভাল বিষয় যে কোনও অফার না দেওয়ার IntStream(তবে LongStreamসমস্ত পূর্ণসংখ্যার ধরণের ক্ষেত্রে ব্যবহারের ) ধারণা বাদ দেওয়া হয়েছে। নোট করুন যে অনুক্রমিক ব্যবহারের ক্ষেত্রে, স্ট্রিমটি মোটেও ব্যবহার করার কারণ Collections.nCopies(8, 1).forEach(i -> System.out.println(i));নেই : একইরকম Collections.nCopies(8, 1).stream().forEach(i -> System.out.println(i));তবে আরও কার্যকর হতে পারেCollections.<Runnable>nCopies(8, () -> System.out.println(1)).forEach(Runnable::run);
হলগার

1
@ হোলজার, এই পরীক্ষাগুলি পরিষ্কার ধরণের প্রোফাইলে করা হয়েছিল, সুতরাং এগুলি বাস্তব বিশ্বের সাথে সম্পর্কিত নয়। সম্ভবত LongStream.rangeআরও খারাপ সঞ্চালিত, কারণ এটি দুটি মানচিত্রগুলি হয়েছে LongFunctionভিতরে, যখন ncopiesসঙ্গে তিন মানচিত্রগুলি হয়েছে IntFunction, ToLongFunctionএবং LongFunction, এইভাবে সব lambdas monomorphic হয়। প্রাক-দূষিত টাইপ প্রোফাইলে এই পরীক্ষাটি চালানো (যা বাস্তব-বিশ্বের ক্ষেত্রে নিকটে) দেখায় যে ncopies1.5x ধীর er
তাগীর ভালিভ

1
অকাল অপ্টিমাইজেশন
এফটিডব্লিউ

1
সম্পূর্ণতার স্বার্থে, একটি বেঞ্চমার্ক দেখতে ভাল লাগবে যা এই দুটি কৌশলকে একটি সাধারণ পুরানো forলুপের সাথে তুলনা করে । আপনার সমাধানটি Streamকোডের চেয়ে দ্রুততর হলেও , আমার অনুমান একটি forলুপ এগুলির দুটিকে একটি উল্লেখযোগ্য ব্যবধানে পরাজিত করবে।
টাইপরার

35

সম্পূর্ণতার জন্য, এবং কারণ আমি নিজেকে সাহায্য করতে পারি না :)

কেবল জাভা স্তরের ভার্বোসেসের সাথে হাসকেলে আপনি যা দেখতে পাবেন তার একটি সীমিত ক্রম উত্পন্ন করা মোটামুটি কাছাকাছি।

IntStream.generate(() -> 1)
         .limit(8)
         .forEach(System.out::println);

() -> 1শুধুমাত্র 1 জেনারেট করবে, এটি কি উদ্দেশ্য? সুতরাং আউটপুট হবে 1 1 1 1 1 1 1 1
খ্রিস্টান উলেনবুম

4
হ্যাঁ, ওপি-র প্রথম হাস্কেল উদাহরণ অনুসারে take 8 (repeat 1)। অ্যাসলিয়াস বেশ সমস্ত অন্যান্য ক্ষেত্রে আচ্ছাদিত।
clstrfsck

3
Stream<T>generateঅন্য কোনও ধরণের সীমাহীন স্ট্রিম পাওয়ার জন্য জেনেরিক পদ্ধতি রয়েছে , যা একইভাবে সীমাবদ্ধ হতে পারে।
zstewart

11

একবার পুনরাবৃত্তি ফাংশন কোথাও হিসাবে সংজ্ঞায়িত করা হয়

public static BiConsumer<Integer, Runnable> repeat = (n, f) -> {
    for (int i = 1; i <= n; i++)
        f.run();
};

আপনি এটি এখন এবং তারপরে এভাবে ব্যবহার করতে পারেন, যেমন:

repeat.accept(8, () -> System.out.println("Yes"));

পেতে এবং হাস্কেল এর সমতুল্য

take 8 (repeat 1)

আপনি লিখতে পারে

StringBuilder s = new StringBuilder();
repeat.accept(8, () -> s.append("1"));

2
এই এক দুর্দান্ত। তবে আমি এটা পরিবর্তন, পুনরাবৃত্তির পিছনে নম্বর প্রদান পরিবর্তিত করে Runnableকরতে Function<Integer, ?>এবং তারপর ব্যবহার f.apply(i)
Fons

0

এটি টাইম ফাংশন বাস্তবায়নের জন্য আমার সমাধান। আমি একজন জুনিয়র তাই আমি স্বীকার করি যে এটি আদর্শ হতে পারে না, কারণ যে কারণেই এটি যদি ভাল ধারণা না হয় তা শুনে আমি আনন্দিত হব।

public static <T extends Object, R extends Void> R times(int count, Function<T, R> f, T t) {
    while (count > 0) {
        f.apply(t);
        count--;
    }
    return null;
}

এখানে কিছু উদাহরণ ব্যবহার:

Function<String, Void> greet = greeting -> {
    System.out.println(greeting);
    return null;
};

times(3, greet, "Hello World!");
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.