দুটি জাভা 8 টি স্ট্রিম বা একটি স্ট্রিমে একটি অতিরিক্ত উপাদান যুক্ত করা


168

আমি এই জাতীয় স্ট্রিম বা অতিরিক্ত উপাদান যুক্ত করতে পারি:

Stream stream = Stream.concat(stream1, Stream.concat(stream2, Stream.of(element));

এবং আমি যেতে যেতে নতুন জিনিস যুক্ত করতে পারি:

Stream stream = Stream.concat(
                       Stream.concat(
                              stream1.filter(x -> x!=0), stream2)
                              .filter(x -> x!=1),
                                  Stream.of(element))
                                  .filter(x -> x!=2);

তবে এটি কুৎসিত, কারণ concatএটি অচল। যদি concatএকটি দৃষ্টান্ত পদ্ধতি ছিল, উপরের উদাহরণগুলোতে অনেক সহজ পড়তে হবে:

 Stream stream = stream1.concat(stream2).concat(element);

এবং

 Stream stream = stream1
                 .filter(x -> x!=0)
                 .concat(stream2)
                 .filter(x -> x!=1)
                 .concat(element)
                 .filter(x -> x!=2);

আমার প্রশ্নটি হ'ল:

1) concatস্থির হওয়ার কোনও ভাল কারণ আছে কি ? বা আমি অনুপস্থিত কিছু সমতুল্য পদ্ধতি আছে?

2) কোনও ক্ষেত্রে, এটি করার আরও ভাল উপায় আছে?


4
দেখে মনে হচ্ছে জিনিসটি সর্বদা এটির মতো ছিল না তবে এর কারণটি আমি খুঁজে পাচ্ছি না।
এডউইন ডালরজো

উত্তর:


126

আপনি যদি স্ট্রিম.কম্যাট এবং স্ট্রিম.ওফের জন্য স্থিতিশীল আমদানি যুক্ত করেন তবে প্রথম উদাহরণটি নীচে লেখা যেতে পারে:

Stream<Foo> stream = concat(stream1, concat(stream2, of(element)));

আমদানি হচ্ছে স্ট্যাটিক পদ্ধতি জেনেরিক নামের সাথে কোডটি পড়া এবং বজায় রাখা (করা কঠিন হয়ে ঘটাতে পারে নামস্থান দূষণ )। সুতরাং, আরও অর্থবহ নাম সহ নিজের স্ট্যাটিক পদ্ধতি তৈরি করা ভাল । তবে, বিক্ষোভের জন্য আমি এই নামের সাথে আঁকড়ে থাকব।

public static <T> Stream<T> concat(Stream<? extends T> lhs, Stream<? extends T> rhs) {
    return Stream.concat(lhs, rhs);
}
public static <T> Stream<T> concat(Stream<? extends T> lhs, T rhs) {
    return Stream.concat(lhs, Stream.of(rhs));
}

এই দুটি স্থিতিশীল পদ্ধতিতে (স্ট্যাটিক আমদানির সাথে optionচ্ছিকভাবে) দুটি উদাহরণ নিম্নরূপ লেখা যেতে পারে:

Stream<Foo> stream = concat(stream1, concat(stream2, element));

Stream<Foo> stream = concat(
                         concat(stream1.filter(x -> x!=0), stream2).filter(x -> x!=1),
                         element)
                     .filter(x -> x!=2);

কোডটি এখন উল্লেখযোগ্যভাবে খাটো। তবে, আমি সম্মত হই যে পাঠযোগ্যতার উন্নতি হয়নি। সুতরাং আমি অন্য একটি সমাধান আছে।


অনেক পরিস্থিতিতে, সংগ্রাহকরা স্রোতের কার্যকারিতা বাড়াতে ব্যবহার করতে পারেন । নীচে দুটি সংগ্রাহক থাকায়, দুটি উদাহরণ নীচে লেখা যেতে পারে:

Stream<Foo> stream = stream1.collect(concat(stream2)).collect(concat(element));

Stream<Foo> stream = stream1
                     .filter(x -> x!=0)
                     .collect(concat(stream2))
                     .filter(x -> x!=1)
                     .collect(concat(element))
                     .filter(x -> x!=2);

আপনার পছন্দসই বাক্য গঠন এবং উপরের সিনট্যাক্সের মধ্যে কেবলমাত্র পার্থক্য হ'ল আপনাকে সংগ্রহ (কনক্যাট (...)) দিয়ে কনক্যাট (...) প্রতিস্থাপন করতে হবে । দুটি স্থিতিশীল পদ্ধতি নিম্নলিখিত হিসাবে প্রয়োগ করা যেতে পারে (স্থির আমদানির সাথে সংযোজনে বিকল্পভাবে ব্যবহৃত হয়):

private static <T,A,R,S> Collector<T,?,S> combine(Collector<T,A,R> collector, Function<? super R, ? extends S> function) {
    return Collector.of(
        collector.supplier(),
        collector.accumulator(),
        collector.combiner(),
        collector.finisher().andThen(function));
}
public static <T> Collector<T,?,Stream<T>> concat(Stream<? extends T> other) {
    return combine(Collectors.toList(),
        list -> Stream.concat(list.stream(), other));
}
public static <T> Collector<T,?,Stream<T>> concat(T element) {
    return concat(Stream.of(element));
}

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


1
concatসংগ্রাহককে আমি খুব বেশি পঠনযোগ্য মনে করি না । এটির নামকরণের একক-প্যারামিটার স্ট্যাটিক পদ্ধতিটি অদ্ভুত বলে মনে collectহয় এবং সংমিশ্রনের জন্য ব্যবহার করাও ।
দিদিয়ের এল

@ নোসিড, এই থ্রেডে সম্ভবত কিছুটা অরথগোনাল প্রশ্ন তবে আপনি কেন দাবি করছেন It's a bad idea to import static methods with names? আমি প্রকৃতপক্ষে আগ্রহী - আমি এটি কোডটি আরও সংক্ষিপ্ত এবং পাঠযোগ্য এবং আমার কাছে জিজ্ঞাসা করা অনেক লোককে একইরকম মনে হয়েছে। কিছু সাধারণ কারণ খারাপ কেন তা উদাহরণ দেওয়ার জন্য যত্নশীল?
কোয়ান্টাম

1
@ কোয়ান্টাম: এর অর্থ কী compare(reverse(getType(42)), of(6 * 9).hashCode())? লক্ষ্য করুন আমি বলিনি যে স্ট্যাটিক আমদানির একটি খারাপ ধারণা আছে, কিন্তু স্ট্যাটিক আমদানির মত জেনেরিক নামের জন্য ofএবং concatহয়।
nosid

1
@ নোসিড: একটি আধুনিক আইডিইতে প্রতিটি স্ট্যাটামেন্টের উপর ঘুরে বেড়াচ্ছেন না কী তাড়াতাড়ি এর অর্থ প্রকাশ করে? যে কোনও হারে, আমি মনে করি এটি বিতর্কিতভাবে সর্বোত্তমভাবে ব্যক্তিগত পছন্দের বক্তব্য হতে পারে, কারণ "জেনেরিক" নামগুলির স্থির আমদানি খারাপ হওয়ার কোনও প্রযুক্তিগত কারণ এখনও আমি দেখতে পাই না - যদি আপনি কোন ক্ষেত্রে প্রোগ্রামিংয়ের জন্য নোটপ্যাড বা ষষ্ঠ (এম) ব্যবহার না করেন তবে আপনার বড় সমস্যা আছে
কোয়ান্টাম

আমি এটি বলার অপেক্ষা রাখে না যে স্কালা এসডিকে আরও ভাল, তবে ... ওফ আমি এটি বলেছিলাম।
eirirlar

165

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

শুরুতে স্ট্রিম.কম্যাট (স্ট্রিম) এর জন্য একটি উদাহরণ পদ্ধতি ছিল

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

এতে তারা প্রবাহটি অসীম হতে পারে এবং যেসব ক্ষেত্রে concক্যবদ্ধতার অর্থ কী হতে পারে সেগুলি থেকে উত্থিত হতে পারে এমন বিষয়গুলি নিয়ে তারা আলোচনা করেন তবে আমি মনে করি না যে এটি সংশোধনের কারণ ছিল।

আপনি এই অন্যান্য থ্রেডে দেখেন যে জেডিকে 8-র কিছু প্রাথমিক ব্যবহারকারী নাল যুক্তি দিয়ে ব্যবহার করার সময় কনক্যাট উদাহরণ পদ্ধতিটির আচরণ সম্পর্কে প্রশ্ন করেছিলেন।

এই অন্যান্য থ্রেডটি প্রকাশ করে, তবে কনক্যাট পদ্ধতির নকশাটি আলোচিত ছিল।

স্ট্রিমস কনক্যাট (স্ট্রিম, স্ট্রিম) এ রিফেক্টার্ড

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

স্ট্রিম.কম্যাট (স্ট্রিম, স্ট্রিম) এ রিফ্যাক্টর

পরবর্তীতে, এটি আবার সরিয়ে নেওয়া হয়েছে থেকে Streamsথেকে Stream, কিন্তু এখনো আবার, যে জন্য কোন ব্যাখ্যা।

সুতরাং, নীচের অংশে, ডিজাইনের কারণটি আমার পক্ষে সম্পূর্ণ পরিষ্কার নয় এবং আমি একটি ভাল ব্যাখ্যা খুঁজে পাইনি। আমার ধারণা আপনি এখনও মেলিং তালিকায় প্রশ্ন জিজ্ঞাসা করতে পারেন।

স্ট্রিম কনকাটেনেশনের জন্য কিছু বিকল্প

মাইকেল হিকসনের এই অন্য থ্রেডে কনক্রিট স্ট্রিমগুলি একত্রিত করার অন্যান্য উপায় সম্পর্কে আলোচনা / জিজ্ঞাসা করেছে

  1. দুটি স্ট্রিম একত্রিত করতে, আমার এটি করা উচিত:

    Stream.concat(s1, s2)

    এটা না:

    Stream.of(s1, s2).flatMap(x -> x)

    ... ঠিক আছে?

  2. দুটিরও বেশি স্ট্রিম একত্রিত করতে, আমার এটি করা উচিত:

    Stream.of(s1, s2, s3, ...).flatMap(x -> x)

    এটা না:

    Stream.of(s1, s2, s3, ...).reduce(Stream.empty(), Stream::concat)

    ... ঠিক আছে?


6
+1 চমৎকার গবেষণা। এবং আমি এটি আমার স্ট্রিম.কম্যাট হিসাবে ভ্যারাগস গ্রহণ হিসাবে ব্যবহার করব:public static <T> Stream<T> concat(Stream<T>... streams) { return Stream.of(streams).reduce(Stream.empty(), Stream::concat);}
মার্জজি

1
আজ আমি আমার নিজস্ব কনক্যাট সংস্করণ লিখেছি এবং ঠিক এরপরেই আমি এই বিষয়টিকে তহবিল দেব। স্বাক্ষরটি কিছুটা আলাদা তবে এর আরও জেনেরিকের জন্য ধন্যবাদ;) উদাহরণস্বরূপ আপনি স্ট্রিম <Integer> এবং স্ট্রিম <ডাবল> স্ট্রিম <নাম্বার> এ একীভূত করতে পারেন। @SafeVarargs private static <T> Stream<T> concat(Stream<? extends T>... streams) { return Stream.of(streams).reduce(Stream.empty(),Stream::concat).map(Function.identity());}
কাঁট

@ কান্ট আপনার Function.identity()মানচিত্রের দরকার কেন ? সর্বোপরি, এটি একই আর্গুমেন্টটি এটি প্রদান করে। ফলস্বরূপ প্রবাহে এর কোনও প্রভাব থাকতে হবে না। আমি কিছু অনুপস্থিত করছি?
এডউইন ডালোরজো

1
আপনি কি আপনার আইডিইতে টাইপ করার চেষ্টা করেছেন? .Map (পরিচয় ()) ব্যতীত আপনি সংকলন ত্রুটি পাবেন। আমি স্ট্রিম <T> তবে বিবৃতিতে ফিরে আসতে চাই: স্ট্রিম <কি ফেরায় return Stream.of(streams).reduce(Stream.empty(),Stream::concat)? প্রসারিত টি>। অতিরিক্ত (Someting <টি> কিছু হয় উপপ্রকার <? প্রসারিত টি>, না অন্য উপায়, তাই এটি ঢালাই নাও হতে পারে) .map(identity())ঢালাই <? টি> টি <টি> পর্যন্ত প্রসারিত। এটি ঘটনামূলক 8 টি 'টার্গেট প্রকারের' পদ্ধতির আর্গুমেন্ট এবং রিটার্নের ধরণের এবং মানচিত্রের স্বাক্ষরের () পদ্ধতির মিশ্রণের জন্য ধন্যবাদ ঘটে। আসলে এটি ফাংশন <<T> পরিচয় ()।
ক্যান্ট

1
@kant আমি করছেন অনেক বিন্দু দেখতে না পান ? extends T, যেহেতু আপনি ব্যবহার করতে পারেন ক্যাপচার রূপান্তরযাইহোক , এখানে আমার গিস্ট কোড স্নিপেট আসুন আসল আলোচনাটি চালিয়ে যান।
এডউইন ডালরজো

12

আমার স্ট্রিমএক্স লাইব্রেরি স্ট্রিম API এর কার্যকারিতা প্রসারিত করে। বিশেষত এটি সংযোজন এবং প্রিপেন্ডের মতো পদ্ধতি সরবরাহ করে যা এই সমস্যাটি সমাধান করে (অভ্যন্তরীণভাবে তারা ব্যবহার করে concat)। এই পদ্ধতিগুলি অন্য কোনও স্ট্রিম বা সংগ্রহ বা ভারার্গস অ্যারে গ্রহণ করতে পারে। আমার গ্রন্থাগারটি ব্যবহার করে আপনার সমস্যাটি এইভাবে সমাধান করা যেতে পারে (নোট x != 0-আদিম স্ট্রিমের জন্য অদ্ভুত লাগবে তা নোট করুন ):

Stream<Integer> stream = StreamEx.of(stream1)
             .filter(x -> !x.equals(0))
             .append(stream2)
             .filter(x -> !x.equals(1))
             .append(element)
             .filter(x -> !x.equals(2));

যাইহোক, আপনার filterঅপারেশনের জন্য একটি শর্টকাটও রয়েছে :

Stream<Integer> stream = StreamEx.of(stream1).without(0)
                                 .append(stream2).without(1)
                                 .append(element).without(2);

9

শুধু কর:

Stream.of(stream1, stream2, Stream.of(element)).flatMap(identity());

যেখানে identity()একটি স্থিতিশীল আমদানি হয় Function.identity()

একাধিক স্ট্রিমকে একটি স্ট্রিমে সংযুক্ত করা স্ট্রিমকে সমতল করার সমান।

তবে দুর্ভাগ্যক্রমে, কোনও কারণে কোনও flatten()পদ্ধতি চালু নেই Stream, সুতরাং আপনাকে flatMap()পরিচয় ফাংশনটি ব্যবহার করতে হবে ।



1

আপনি যদি তৃতীয় পক্ষের গ্রন্থাগারগুলি ব্যবহার করতে আপত্তি করেন না তবে সাইক্লোপস-প্রতিক্রিয়াটির একটি বর্ধিত স্ট্রিম প্রকার রয়েছে যা আপনাকে অ্যাপেন্ড / প্রিপেন্ড অপারেটরগুলির মাধ্যমে কেবল এটি করতে দেয়।

পৃথক মান, অ্যারে, পুনরাবৃত্তিযোগ্য, স্ট্রিম বা প্রতিক্রিয়াশীল-স্ট্রিম প্রকাশকগুলিকে উদাহরণ পদ্ধতি হিসাবে সংযোজন এবং সংশোধন করা যেতে পারে।

Stream stream = ReactiveSeq.of(1,2)
                           .filter(x -> x!=0)
                           .append(ReactiveSeq.of(3,4))
                           .filter(x -> x!=1)
                           .append(5)
                           .filter(x -> x!=2);

[প্রকাশ আমি সাইক্লোপস-রিএ্যাক্টের প্রধান বিকাশকারী]


1

দিন শেষে আমি স্ট্রিমগুলির সংমিশ্রণে আগ্রহী নই, তবে all সমস্ত স্ট্রিমের প্রতিটি উপাদানকে প্রক্রিয়াজাত করার সম্মিলিত ফলাফল অর্জনে।

স্ট্রিমগুলির সংমিশ্রণটি জটিল (যেমন এই থ্রেড) প্রমাণিত হতে পারে, তবে তাদের প্রক্রিয়াজাতকরণের ফলাফলগুলি একত্রিত করা মোটামুটি সহজ।

সমাধানের মূল কীটি হ'ল আপনার নিজস্ব সংগ্রাহক তৈরি করা এবং এটি নিশ্চিত করা যে নতুন সংগ্রাহকের জন্য সরবরাহকারী ফাংশনটি প্রতিবার একই সংগ্রহ ফেরত দেয় ( নতুন নয় ), নীচের কোডটি এই পদ্ধতির চিত্রিত করে।

package scratchpad;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collector;
import java.util.stream.Stream;

public class CombineStreams {
    public CombineStreams() {
        super();
    }

    public static void main(String[] args) {
        List<String> resultList = new ArrayList<>();
        Collector<String, List<String>, List<String>> collector = Collector.of(
                () -> resultList,
                (list, item) -> {
                    list.add(item);
                },
                (llist, rlist) -> {
                    llist.addAll(rlist);
                    return llist;
                }
        );
        String searchString = "Wil";

        System.out.println("After processing first stream\n"
                + createFirstStream().filter(name -> name.contains(searchString)).collect(collector));
        System.out.println();

        System.out.println("After processing second stream\n"
                + createSecondStream().filter(name -> name.contains(searchString)).collect(collector));
        System.out.println();

        System.out.println("After processing third stream\n"
                + createThirdStream().filter(name -> name.contains(searchString)).collect(collector));
        System.out.println();

    }

    private static Stream<String> createFirstStream() {
        return Arrays.asList(
                "William Shakespeare",
                "Emily Dickinson",
                "H. P. Lovecraft",
                "Arthur Conan Doyle",
                "Leo Tolstoy",
                "Edgar Allan Poe",
                "Robert Ervin Howard",
                "Rabindranath Tagore",
                "Rudyard Kipling",
                "Seneca",
                "John Donne",
                "Sarah Williams",
                "Oscar Wilde",
                "Catullus",
                "Alfred Tennyson",
                "William Blake",
                "Charles Dickens",
                "John Keats",
                "Theodor Herzl"
        ).stream();
    }

    private static Stream<String> createSecondStream() {
        return Arrays.asList(
                "Percy Bysshe Shelley",
                "Ernest Hemingway",
                "Barack Obama",
                "Anton Chekhov",
                "Henry Wadsworth Longfellow",
                "Arthur Schopenhauer",
                "Jacob De Haas",
                "George Gordon Byron",
                "Jack London",
                "Robert Frost",
                "Abraham Lincoln",
                "O. Henry",
                "Ovid",
                "Robert Louis Stevenson",
                "John Masefield",
                "James Joyce",
                "Clark Ashton Smith",
                "Aristotle",
                "William Wordsworth",
                "Jane Austen"
        ).stream();
    }

    private static Stream<String> createThirdStream() {
        return Arrays.asList(
                "Niccolò Machiavelli",
                "Lewis Carroll",
                "Robert Burns",
                "Edgar Rice Burroughs",
                "Plato",
                "John Milton",
                "Ralph Waldo Emerson",
                "Margaret Thatcher",
                "Sylvie d'Avigdor",
                "Marcus Tullius Cicero",
                "Banjo Paterson",
                "Woodrow Wilson",
                "Walt Whitman",
                "Theodore Roosevelt",
                "Agatha Christie",
                "Ambrose Bierce",
                "Nikola Tesla",
                "Franz Kafka"
        ).stream();
    }
}

0

আপনার নিজের কনক্যাট পদ্ধতিটি লেখার বিষয়ে কীভাবে?

public static Stream<T> concat(Stream<? extends T> a, 
                               Stream<? extends T> b, 
                               Stream<? extends T> args)
{
    Stream<T> concatenated = Stream.concat(a, b);
    for (Stream<T> stream : args)
    {
        concatenated = Stream.concat(concatenated, stream);
    }
    return concatenated;
}

এটি অন্তত আপনার প্রথম উদাহরণটিকে আরও অনেক বেশি পাঠযোগ্য করে তোলে।


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