ওয়ান-লাইনারে স্ট্রিম / তালিকার শেষ উপাদানটি পান


118

নীচের কোডটিতে আমি কীভাবে একটি স্ট্রিম বা তালিকার শেষ উপাদানটি পেতে পারি?

data.careasএকটি কোথায় List<CArea>:

CArea first = data.careas.stream()
                  .filter(c -> c.bbox.orientationHorizontal).findFirst().get();

CArea last = data.careas.stream()
                 .filter(c -> c.bbox.orientationHorizontal)
                 .collect(Collectors.toList()).; //how to?

আপনি দেখতে পাচ্ছেন যে প্রথম উপাদানটি, একটি নির্দিষ্ট সহ filter, পাওয়া শক্ত নয়।

তবে ওয়ান-লাইনারে শেষ উপাদানটি পাওয়া সত্যিকারের ব্যথা:

  • দেখে মনে হচ্ছে আমি এ থেকে সরাসরি এটি পেতে পারি না Stream। (এটি কেবল সীমাবদ্ধ স্ট্রিমগুলির জন্য অর্থবহ হবে)
  • এছাড়া মনে হচ্ছে আপনি ভালো জিনিস পেতে পারে না first()এবং last()থেকে Listইন্টারফেস, যা সত্যিই ব্যাথা হয়।

ইন্টারফেসে একটি first()এবং last()পদ্ধতি সরবরাহ না করার জন্য আমি কোনও যুক্তি দেখতে পাচ্ছি না List, কারণ সেখানে উপাদানগুলি আদেশ করা হয়েছে, এবং এরপরে আকারটিও জানা গেছে।

তবে আসল উত্তর অনুসারে: সসীমের শেষ উপাদানটি কীভাবে পাবেন Stream?

ব্যক্তিগতভাবে, এটি আমার কাছে পাওয়া সবচেয়ে নিকটতম:

int lastIndex = data.careas.stream()
        .filter(c -> c.bbox.orientationHorizontal)
        .mapToInt(c -> data.careas.indexOf(c)).max().getAsInt();
CArea last = data.careas.get(lastIndex);

তবে এতে জড়িত থাকে, indexOfপ্রতিটি উপাদান ব্যবহার করে, যা সম্ভবত আপনি চান না কারণ এটি কার্য সম্পাদনকে ক্ষতিগ্রস্থ করতে পারে।


10
পেয়ারা সরবরাহ করে Iterables.getLastযা গ্রহণযোগ্য হয় তবে এটি কাজ করতে অনুকূল হয় List। একটি পোষা peeve যে এটি নেই getFirstStreamসাধারণভাবে এপিআই সুবিধা পদ্ধতি প্রচুর বাদ ভয়ঙ্করভাবে পায়ুসংক্রান্ত হয়। সি # এর লিনক, বিপরীতে, প্রদান করে খুশি .Last()এবং এমনকি .Last(Func<T,Boolean> predicate)এটি অসীম সংখ্যাগুণকে সমর্থন করেও।
আলেকসান্দ্র ডাবিনস্কি

@ আলেকসান্ডারডুবিনস্কি উচ্চারণ করেছেন তবে পাঠকদের জন্য একটি নোট। উভয়ই খুব আলাদা দৃষ্টান্তে সম্পন্ন Streamহওয়ায় এপিআই সম্পূর্ণরূপে তুলনীয় নয় LINQ। এটি খারাপ বা আরও ভাল নয় এটি একেবারেই আলাদা। এবং অবশ্যই কিছু পদ্ধতি অনুপস্থিত না কারণ ওরাকল
দেবগণ

1
সত্যিকারের ওয়ান-লাইনারের জন্য, এই থ্রেডটি কার্যকর হতে পারে।
কোয়ান্টাম

উত্তর:


185

স্ট্রিম :: হ্রাস পদ্ধতি সহ শেষ উপাদানটি পাওয়া সম্ভব । নিম্নলিখিত তালিকায় সাধারণ ক্ষেত্রে একটি সর্বনিম্ন উদাহরণ রয়েছে:

Stream<T> stream = ...; // sequential or parallel stream
Optional<T> last = stream.reduce((first, second) -> second);

এই প্রয়োগগুলি সমস্ত আদেশযুক্ত স্ট্রিমের জন্য কাজ করে ( তালিকাগুলি থেকে তৈরি স্ট্রিম সহ )। জন্য unordered স্ট্রিম এটা অনির্দিষ্ট সুস্পষ্ট কারন যা উপাদান ফেরত পাঠানো হবে জন্য।

বাস্তবায়ন উভয় ক্রমিক এবং সমান্তরাল স্ট্রিমের জন্য কাজ করে । এটি প্রথম নজরে আশ্চর্যজনক হতে পারে, এবং দুর্ভাগ্যক্রমে ডকুমেন্টেশনটি এটি স্পষ্টভাবে উল্লেখ করে না। তবে এটি স্ট্রিমগুলির একটি গুরুত্বপূর্ণ বৈশিষ্ট্য, এবং আমি এটি পরিষ্কার করার চেষ্টা করি:

  • স্ট্রিম পদ্ধতির জাভাডোক :: রাষ্ট্রগুলিকে হ্রাস করে, এটি " ক্রমানুসারে সম্পাদন করতে সীমাবদ্ধ নয় "
  • জাভাডোকেরও এটির প্রয়োজন যে "সংযোজক ফাংশনটি অবশ্যই দুটি মানের সংমিশ্রণের জন্য একটি সহযোগী , অ-হস্তক্ষেপ , স্টেটলেস ফাংশন" হতে পারে , যা স্পষ্টতই ল্যাম্বডা অভিব্যক্তির ক্ষেত্রে এটি (first, second) -> second
  • হ্রাস কার্যক্রমের জাভাডোক বলে: "স্ট্রিম ক্লাসগুলিতে সাধারণ হ্রাস অপারেশনগুলির একাধিক রূপ রয়েছে, যাকে হ্রাস () এবং সংগ্রহ () সংগ্রহ করে [..]" এবং "একটি সঠিকভাবে নির্মিত হ্রাস অপারেশন সহজাতভাবে সমান্তরাল হয় , যতক্ষণ পর্যন্ত কার্য (গুলি) ) ব্যবহার উপাদান প্রক্রিয়া মিশুক এবং আড়ম্বরহীন । "

ঘনিষ্ঠভাবে সম্পর্কিত ডকুমেন্টেশন সংগ্রাহক আরও বেশি স্পষ্ট হল: "যে নিশ্চিত করার জন্য অনুক্রমিক এবং সমান্তরাল মৃত্যুদণ্ড কার্যকর উত্পাদন সমতুল্য ফলাফল , সংগ্রাহক ফাংশন একটি পরিচয় এবং সন্তুষ্ট করা আবশ্যক associativity সীমাবদ্ধতার।"


মূল প্রশ্নে ফিরে যান: নিম্নলিখিত কোডটি ভেরিয়েবলের শেষ উপাদানটির একটি রেফারেন্স সঞ্চয় করে lastএবং স্ট্রিমটি ফাঁকা থাকলে ব্যতিক্রম ছুঁড়ে দেয়। জটিলতা প্রবাহের দৈর্ঘ্যে লিনিয়ার।

CArea last = data.careas
                 .stream()
                 .filter(c -> c.bbox.orientationHorizontal)
                 .reduce((first, second) -> second).get();

ভাল লাগল, ধন্যবাদ! আপনি কি জানেন যে _প্যারামিটারের প্রয়োজন নেই এমন ক্ষেত্রে সম্ভবত কোনও নাম বাদ দেওয়া (সম্ভবত কোনও বা অনুরূপ ব্যবহার করে ) করা উচিত কিনা ? সুতরাং হবে: .reduce((_, current) -> current)কেবলমাত্র যদি বৈধ বাক্য গঠন হয়
স্কিভি

2
@ স্কিভি আপনি যে কোনও আইনী পরিবর্তনশীল নাম ব্যবহার করতে পারেন, উদাহরণস্বরূপ: .reduce(($, current) -> current)বা .reduce((__, current) -> current)(ডাবল আন্ডারস্কোর)।
Assylias

2
প্রযুক্তিগতভাবে, এটি কোনও স্ট্রিমের জন্য কাজ করতে পারে না। আপনি যে ডকুমেন্টেশনটির দিকে ইঙ্গিত করেছেন, সেই সাথে এনকাউন্টার অর্ডার মানলে Stream.reduce(BinaryOperator<T>)তা উল্লেখ করা যায় না reduceএবং একটি টার্মিনাল অপারেশন স্ট্রিমের অর্ডার দেওয়া সত্ত্বেও এনকাউন্টার অর্ডার উপেক্ষা করতে পারে। একদিকে যেমন, "অভিযাত্রী" শব্দটি স্ট্রিম জাভাদোকগুলিতে উপস্থিত হয় না, সুতরাং এর অনুপস্থিতি আমাদের বেশি কিছু বলে না।
আলেকসান্দ্র ডাবিনস্কি

2
@AleksandrDubinsky: ঠিক, ডকুমেন্টেশন উল্লেখ না বিনিময় , কারণ এটি জন্য প্রাসঙ্গিক নয় কমাতে অপারেশন। গুরুত্বপূর্ণ অংশটি হ'ল: "[..] সঠিকভাবে নির্মিত কমানো অপারেশন সহজাতভাবে সমান্তরাল হয়, যতক্ষণ না উপাদানগুলি প্রক্রিয়া করতে ব্যবহৃত ফাংশনগুলি সংঘবদ্ধ হয় [..]"
nosid

2
@ আলেকসান্দ্র ডাবিনস্কি: অবশ্যই, এটি একটি "অনুমানের তাত্ত্বিক প্রশ্ন" নয়। এটি reduce((a,b)->b)সর্বশেষ উপাদানটি (অবশ্যই একটি আদেশযুক্ত প্রবাহের) পাওয়ার সঠিক সমাধান হওয়ার মধ্যে পার্থক্য তৈরি করে না। ব্রায়ান গয়েটসের বক্তব্যটি একটি বিষয়বস্তু তোলে, আরও এপিআই ডকুমেন্টেশন বলে যে reduce("", String::concat)স্ট্রিং কনটেনটেশনের জন্য একটি অদক্ষ কিন্তু সঠিক সমাধান, যা মুখোমুখি আদেশের রক্ষণাবেক্ষণের ইঙ্গিত দেয় intention উদ্দেশ্য সুপরিচিত, ডকুমেন্টেশনটি ধরে রাখতে হবে।
হলগার

42

আপনার যদি সংগ্রহ থাকে (বা আরও সাধারণ একটি আইটেবল) আপনি গুগল পেয়ারা ব্যবহার করতে পারেন

Iterables.getLast(myIterable)

হ্যান্ডেল অনেলাইনার হিসাবে


1
এবং আপনি সহজেই কোনও স্ট্রিমটিকে একটি পুনরাবৃত্তযোগ্য হিসাবে রূপান্তর করতে পারেন:Iterables.getLast(() -> data.careas.stream().filter(c -> c.bbox.orientationHorizontal).iterator())
shmosel

10

একটি লাইনার (প্রবাহের প্রয়োজন নেই;):

Object lastElement = list.get(list.size()-1);

30
তালিকাটি ফাঁকা থাকলে এই কোডটি ছুঁড়ে দেওয়া হবে ArrayIndexOutOfBoundsException
ড্রাগন

8

পেয়ারার ক্ষেত্রে এই মামলার জন্য উত্সর্গীকৃত পদ্ধতি রয়েছে:

Stream<T> stream = ...;
Optional<T> lastItem = Streams.findLast(stream);

এটি এর সমতুল্য stream.reduce((a, b) -> b)তবে নির্মাতারা দাবি করেছেন যে এটির আরও ভাল পারফরম্যান্স রয়েছে।

ডকুমেন্টেশন থেকে :

এই পদ্ধতির রানটাইমটি ও (লগ এন) এবং ও (এন) এর মধ্যে থাকবে, দক্ষতার সাথে বিভাজনযোগ্য স্ট্রিমগুলিতে আরও ভাল সম্পাদন করবে।

এটি উল্লেখ করার মতো বিষয় যে স্ট্রিমটি আনর্ডার্ড করা থাকলে এই পদ্ধতির মতো আচরণ করে findAny()


1
@ Kaেকা কোজলোভ ধরণের ... হলার এর সাথে এখানে
ইউজিন

0

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

    final Queue<Integer> queue = new LinkedList<>();
    final int N=5;
    list.stream().peek((z) -> {
        queue.offer(z);
        if (queue.size() > N)
            queue.poll();
    }).count();

আরেকটি বিকল্প হ'ল একটি সারি হিসাবে পরিচয় ব্যবহার করে কমানোর অপারেশন ব্যবহার করা।

    final int lastN=3;
    Queue<Integer> reduce1 = list.stream()
    .reduce( 
        (Queue<Integer>)new LinkedList<Integer>(), 
        (m, n) -> {
            m.offer(n);
            if (m.size() > lastN)
               m.poll();
            return m;
    }, (m, n) -> m);

    System.out.println("reduce1 = " + reduce1);

-1

আপনি নীচে হিসাবে স্কিপ () ফাংশন ব্যবহার করতে পারেন ...

long count = data.careas.count();
CArea last = data.careas.stream().skip(count - 1).findFirst().get();

এটি ব্যবহার করা অত্যন্ত সহজ।


দ্রষ্টব্য: বিশাল সংগ্রহ (কয়েক মিলিয়ন এন্ট্রি) নিয়ে কাজ করার সময় আপনার স্ট্রিমের "স্কিপ" এর উপর ভরসা করা উচিত নয়, কারণ "স্কিপ" এনটিএম নম্বর না আসা পর্যন্ত সমস্ত উপাদানগুলির মাধ্যমে পুনরাবৃত্তি করে প্রয়োগ করা হয়। এটা চেষ্টা করেছি. সাধারণ গেট-বাই-ইনডেক্স অপারেশনের তুলনায় পারফরম্যান্সে খুব হতাশ হয়েছিল।
java.is.for.desktop

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