জাভা 8 লাম্বদা পেতে এবং তালিকা থেকে উপাদান সরান


91

উপাদানের একটি তালিকা দেওয়া, আমি একটি প্রদত্ত সম্পত্তি সহ উপাদানটি পেতে এবং এটি তালিকা থেকে মুছে ফেলতে চাই। সবচেয়ে ভাল সমাধান আমি খুঁজে পেয়েছি:

ProducerDTO p = producersProcedureActive
                .stream()
                .filter(producer -> producer.getPod().equals(pod))
                .findFirst()
                .get();
producersProcedureActive.remove(p);

ল্যাম্বডা এক্সপ্রেশনে একত্রিত হওয়া এবং সরানো কি সম্ভব?


9
এটি কেবল কখন পরিবর্তে কেবল একটি লুপ এবং পুনরায় ব্যবহার করতে হবে তার একটি ক্লাসিক কেসের মতো বলে মনে হচ্ছে।
ক্রাইলিস-সতর্কতাবাদী-

4
@ ক্রিলিস আমি দয়া করে একমত নই;) আমরা অত্যাবশ্যক প্রোগ্রামিংয়ের জন্য এতটাই অভ্যস্ত, যে অন্য কোনও উপায়ে খুব বিদেশী বলে মনে হচ্ছে sounds কল্পনা করুন যে বাস্তবতা যদি অন্যভাবে ঘটেছিল: আমরা কার্যকরী প্রোগ্রামিংয়ের জন্য খুব ব্যবহৃত এবং জাভাতে একটি নতুন আবশ্যকীয় দৃষ্টান্ত যুক্ত করা হয়েছে। আপনি কি বলবেন যে এটি স্ট্রিম, পূর্বাভাস এবং বিকল্পগুলির জন্য ক্লাসিক কেস হবে?
এফপিএস

9
get()এখানে ফোন করবেন না ! এটি খালি কিনা তা আপনার কোনও ধারণা নেই। উপাদানটি না থাকলে আপনি একটি ব্যতিক্রম ছুঁড়ে ফেলবেন। পরিবর্তে, নিরাপদ পদ্ধতিগুলির মধ্যে একটি যেমন আইপ্রেসড, orElse, orElseGet, বা orElseThrow ব্যবহার করুন।
ব্রায়ান গয়েটজ

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

শুধু নির্মল: আপনি সব উপাদান সরাতে চান list, যার জন্য Predicateসত্য বা (ক সম্ভবত শূন্য, এক বা অনেক উপাদানের) শুধুমাত্র প্রথম?
কেদার মহসওয়াদে

উত্তর:


154

তালিকা থেকে উপাদান সরান

objectA.removeIf(x -> conditions);

যেমন:

objectA.removeIf(x -> blockedWorkerIds.contains(x));

List<String> str1 = new ArrayList<String>();
str1.add("A");
str1.add("B");
str1.add("C");
str1.add("D");

List<String> str2 = new ArrayList<String>();
str2.add("D");
str2.add("E");

str1.removeIf(x -> str2.contains(x)); 

str1.forEach(System.out::println);

আউটপুট: এ বি সি


আমি এটিকে সর্বোত্তম উত্তর হিসাবে পরামর্শ
দেব

4
এটা খুব ঝরঝরে। আপনার নিজের অবজেক্টগুলির জন্য এটি না করা হলে আপনাকে সমান / হ্যাশকোড প্রয়োগ করতে হবে। (এই উদাহরণে স্ট্রিং ব্যবহৃত হয় যা সেগুলি ডিফল্টরূপে থাকে)।
bram000

17
আইএমএইচও উত্তরটি "পান" অংশটি বিবেচনা করে না: removeIfসংগ্রহ থেকে উপাদানগুলি সরিয়ে ফেলার একটি দুর্দান্ত সমাধান, তবে এটি সরানো উপাদানটিকে ফেরত দেয় না।
মার্কো স্ট্রেমেজি

জাভা অ্যারেলিস্ট থেকে কোনও অবজেক্ট বাদ দিতে এটি খুব সাধারণ মোড। অনেক কিছু। আমাকে ভাল কাজ।
মার্সেলো রেবাউস

4
এটি প্রশ্নের উত্তর দেয় না। প্রয়োজনীয়তাটি হ'ল উপাদানটি তালিকা থেকে সরানো এবং সরানো আইটেম / আইটেমগুলিকে একটি নতুন তালিকায় নিয়ে যাওয়া।
শানিকা এডিরিউয়ের

35

যদিও থ্রেডটি বেশ পুরানো, তবুও সমাধান দেওয়ার - ব্যবহারের চিন্তাভাবনা করেছে Java8

removeIfফাংশন ব্যবহার করুন । সময় জটিলতা হয়O(n)

producersProcedureActive.removeIf(producer -> producer.getPod().equals(pod));

এপিআই রেফারেন্স: ডক্স সরান

অনুমান: producersProcedureActiveList

দ্রষ্টব্য: এই পদ্ধতির সাহায্যে আপনি মুছে ফেলা আইটেমটি ধরে রাখতে পারবেন না।


তালিকা থেকে উপাদান মোছার পাশাপাশি, ওপি এখনও উপাদানটির একটি রেফারেন্স চায়।
eee

@ আইই: এটি উল্লেখ করার জন্য অনেক ধন্যবাদ। ওপির মূল প্রশ্নটি থেকে আমি সেই অংশটি মিস করেছি।
asifsid88

কেবল এটি লক্ষ করার জন্য শর্তের সাথে মেলে এমন সমস্ত আইটেম সরিয়ে ফেলবে। তবে ওপিতে কেবলমাত্র প্রথম আইটেমটি অপসারণ করা দরকার (ওপিতে ফাইন্ড ফার্স্ট () ব্যবহৃত হয়েছে)
ন্যান্টিটভ

18

কাজটি সম্পাদন করতে ভ্যানিলা জাভা পুনরায় ব্যবহার করার বিষয়টি বিবেচনা করুন:

public static <T> T findAndRemoveFirst(Iterable<? extends T> collection, Predicate<? super T> test) {
    T value = null;
    for (Iterator<? extends T> it = collection.iterator(); it.hasNext();)
        if (test.test(value = it.next())) {
            it.remove();
            return value;
        }
    return null;
}

সুবিধা :

  1. এটা সহজ এবং সুস্পষ্ট।
  2. এটি কেবল একবারে এবং কেবলমাত্র ম্যাচের উপাদান পর্যন্ত চলে।
  3. আপনি সমর্থন Iterableছাড়াই যেকোনও ক্ষেত্রে এটি করতে পারেন (কমপক্ষে যারা তাদের পুনরুক্তিতে প্রয়োগ করছেন)stream()remove()

অসুবিধাগুলি :

  1. আপনি এটি একক অভিব্যক্তি হিসাবে জায়গায় করতে পারবেন না (সহায়ক পদ্ধতি বা ভেরিয়েবল প্রয়োজনীয়)

জন্য

ল্যাম্বডা এক্সপ্রেশনে একত্রিত হওয়া এবং সরানো কি সম্ভব?

অন্যান্য উত্তরগুলি পরিষ্কারভাবে দেখায় যে এটি সম্ভব, তবে আপনার সচেতন হওয়া উচিত

  1. অনুসন্ধান এবং অপসারণ এই তালিকাটিকে দুইবার অতিক্রম করতে পারে
  2. ConcurrentModificationException তালিকা থেকে উপাদানটি পুনরাবৃত্ত হওয়ার সময় নিক্ষেপ করা হতে পারে

4
আমি এই সমাধানটি পছন্দ করি তবে নোট করুন যে এটির একটি মারাত্মক অসুবিধা রয়েছে যা আপনি মিস করেছেন: অনেকগুলি পরীক্ষামূলক বাস্তবায়নের এমন remove()পদ্ধতি রয়েছে যা ইউওই ফেলে দেয়। (জেডিকে সংগ্রহের জন্য অবশ্যই নয়, তবে আমি "যে কোনও আইট্রেটেবলের জন্য কাজ করে" বলা অনুচিত বলে মনে করি।)
ব্রায়ান

আমি মনে করি আমরা ধরে নিতে পারি যে যদি কোনও উপাদান সাধারণভাবে সরিয়ে ফেলা যায় তবে তা পুনরুক্তিকারী দ্বারা
ভ্যাসিলি লিয়াসকভস্কি

4
আপনি এটি ধরে নিতে পারেন, তবে শতাধিক পুনরাবৃত্তি বাস্তবায়নের দিকে তাকালে এটি একটি খারাপ ধারণা হবে। (আমি এখনও এই পদ্ধতির পছন্দ করি; আপনি এটি কেবলমাত্র বেশি বিক্রি করছেন))
ব্রায়ান গোয়েজ

4
@Brian Goetz: defaultবাস্তবায়ন removeIfতোলে একই ধৃষ্টতা কিন্তু, অবশ্যই, এটা সংজ্ঞায়িত হয়েছে তা Collectionবদলে Iterable...
হোলগার

14

সরাসরি সমাধান ডাকা হবে ifPresent(consumer)ঐচ্ছিক দ্বারা ফিরে findFirst()। Consumerচ্ছিক খালি না হলে এই গ্রাহককে ডাকা হবে। সুবিধাটিও হ'ল এটি যদি সন্ধানী ক্রিয়াকলাপটি আপনার বর্তমান কোডের মতো খালি alচ্ছিকভাবে ফিরে আসে তবে এটি ব্যতিক্রম করবে না; পরিবর্তে, কিছুই ঘটবে না।

আপনি সরানো মান ফেরত পাঠাতে চান, আপনি যা করতে পারেন কলিং ফলাফলের সাথে প্রাসঙ্গিক :mapOptionalremove

producersProcedureActive.stream()
                        .filter(producer -> producer.getPod().equals(pod))
                        .findFirst()
                        .map(p -> {
                            producersProcedureActive.remove(p);
                            return p;
                        });

তবে নোট করুন যে remove(Object)অপারেশনটি আবার সরানোর জন্য উপাদানটি সন্ধানের জন্য তালিকাটিকে অতিক্রম করবে। যদি আপনার মতো এলোমেলো অ্যাক্সেসের সাথে একটি তালিকা ArrayListথাকে তবে তালিকার সূচীগুলির উপরে একটি স্ট্রিম তৈরি করা ভাল এবং ভালির সাথে প্রথম সূচকটি খুঁজে পাওয়া ভাল:

IntStream.range(0, producersProcedureActive.size())
         .filter(i -> producersProcedureActive.get(i).getPod().equals(pod))
         .boxed()
         .findFirst()
         .map(i -> producersProcedureActive.remove((int) i));

এই সমাধানের সাথে, remove(int)অপারেশন সরাসরি সূচকগুলিতে পরিচালনা করে।


4
এটি কোনও লিঙ্কযুক্ত তালিকার জন্য প্যাথলজিকাল।
ক্রাইলিস -কোটিরিওপটিস্টিস্টিক-

4
@ ক্রাইলিস সূচক সমাধানটি সত্যই হবে। তালিকার প্রয়োগের উপর নির্ভর করে একজন একে অপরের চেয়ে বেশি পছন্দ করবে। একটি ছোট সম্পাদনা করেছেন।
টুনাকি

4
@ ক্রাইলিস: আপনার ক্ষেত্রে LinkedListসম্ভবত স্ট্রিম এপিআই ব্যবহার করা উচিত নয় কারণ কমপক্ষে দু'বার ট্র্যাভ্রেস না করেই কোনও সমাধান নেই। তবে আমি এমন কোনও বাস্তব জীবনের দৃশ্যের কথা জানি না যেখানে কোনও লিঙ্কযুক্ত তালিকার একাডেমিক সুবিধা তার প্রকৃত ওভারহেডকে ক্ষতিপূরণ দিতে পারে। তাই সহজ সমাধানটি কখনও ব্যবহার না করা LinkedList
হলগার

4
ওহ এতগুলি সম্পাদনা… এখন প্রথম সমাধান মুছে ফেলা উপাদান সরবরাহ করে না কারণ remove(Object)কেবল booleanসরানোর কোনও উপাদান রয়েছে কি না তা কেবল তা জানিয়ে দেয়।
হলগার

4
@ মার্কো স্ট্রেমেজি: দুর্ভাগ্যক্রমে, মন্তব্যটি এটি ব্যাখ্যা করে তা সরিয়ে দেওয়া হয়েছে। boxed()আপনি ছাড়া এমন কিছু পান OptionalIntযা কেবলমাত্র mapথেকে শুরু intকরে int। বিপরীতে IntStream, কোন mapToObjপদ্ধতি নেই। এর সাথে boxed(), আপনি এমন একটি পাবেন Optional<Integer>যা mapএকটি স্বেচ্ছাসেবী বস্তুতে মঞ্জুরি দেয় , অর্থাত্‍ ProducerDTOফিরে আসে remove(int)। থেকে কাস্ট করার Integerজন্য intমধ্যবর্তী দুর্বোধ্য করা প্রয়োজন remove(int)এবং remove(Object)
হলগার

9

ব্যবহার জাভা 8 এর ফিল্টার ব্যবহার করতে পারে এবং আপনি যদি পুরানো তালিকাটি পরিবর্তন করতে না চান তবে অন্য তালিকা তৈরি করতে পারেন:

List<ProducerDTO> result = producersProcedureActive
                            .stream()
                            .filter(producer -> producer.getPod().equals(pod))
                            .collect(Collectors.toList());

5

আমি নিশ্চিত এটি একটি অপ্রিয় উত্তর হবে, তবে এটি কার্যকর ...

ProducerDTO[] p = new ProducerDTO[1];
producersProcedureActive
            .stream()
            .filter(producer -> producer.getPod().equals(pod))
            .findFirst()
            .ifPresent(producer -> {producersProcedureActive.remove(producer); p[0] = producer;}

p[0] হয় পাওয়া উপাদানটিকে ধরে রাখবে বা নাল হবে।

এখানে "কৌতুক" কার্যকরভাবে চূড়ান্ত, তবে এর প্রথম উপাদানটি সেট করে এমন অ্যারে রেফারেন্স ব্যবহার করে "কার্যকরভাবে চূড়ান্ত" সমস্যাটি সমাধান করছে।


4
এটি এই ক্ষেত্রে, এটি খুব খারাপ নয়, তবে কেবল কল .orElse(null)করার জন্য কল করার ProducerDTOবা সম্ভাব্যতার চেয়ে কোনও উন্নতি নয় null...
হোলগার

সেক্ষেত্রে কেবল থাকা .orElse(null)এবং থাকাও সহজ হতে পারে if, না?
টুনাকি

@ হোলগার তবে কীভাবে আপনি remove()ব্যবহার করে খুব অনুরোধ করতে পারেন orElse(null)?
বোহেমিয়ান

4
শুধু ফলাফল ব্যবহার করুন। if(p!=null) producersProcedureActive.remove(p);এটি এখনও আপনার ifPresentকলটিতে ল্যাম্বডা অভিব্যক্তির চেয়ে কম ।
হলগার

@ হোলগার আমি প্রশ্নের লক্ষ্যটিকে একাধিক বিবৃতি এড়ানো হিসাবে ব্যাখ্যা করেছি - অর্থাত্ 1 লাইনের সমাধান
বোহেমিয়ান

4

সঙ্গে অন্ধকার সংগ্রহগুলি আপনি ব্যবহার করতে পারেন detectIndexসহ remove(int)কোনো java.util.List উপর।

List<Integer> integers = Lists.mutable.with(1, 2, 3, 4, 5);
int index = Iterate.detectIndex(integers, i -> i > 2);
if (index > -1) {
    integers.remove(index);
}

Assert.assertEquals(Lists.mutable.with(1, 2, 4, 5), integers);

আপনি যদি MutableListগ্রহগ্রাহ সংগ্রহ থেকে প্রকারটি ব্যবহার করেন তবে আপনি detectIndexসরাসরি তালিকায় পদ্ধতিটি কল করতে পারেন ।

MutableList<Integer> integers = Lists.mutable.with(1, 2, 3, 4, 5);
int index = integers.detectIndex(i -> i > 2);
if (index > -1) {
    integers.remove(index);
}

Assert.assertEquals(Lists.mutable.with(1, 2, 4, 5), integers);

দ্রষ্টব্য: আমি গ্রহগ্রাহ সংগ্রহের প্রতিশ্রুতিবদ্ধ


2

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

জাভা স্ট্রিমিং এপিআই পার্টিশন ব্যবহার করে আমরা এটি কীভাবে করতে পারি তা এখানে।

Map<Boolean, List<ProducerDTO>> classifiedElements = producersProcedureActive
    .stream()
    .collect(Collectors.partitioningBy(producer -> producer.getPod().equals(pod)));

// get two new lists 
List<ProducerDTO> matching = classifiedElements.get(true);
List<ProducerDTO> nonMatching = classifiedElements.get(false);

// OR get non-matching elements to the existing list
producersProcedureActive = classifiedElements.get(false);

এই ভাবে আপনি কার্যকর তালিকা থেকে ফিল্টার করা উপাদানগুলি কার্যকর তালিকা থেকে সরান এবং তাদের একটি নতুন তালিকায় যুক্ত করুন।

পড়ুন 5.2। Collectors.partitioningBy বিভাগে এই নিবন্ধটি


1

অন্যরা যেমন পরামর্শ দিয়েছে, এটি লুপ এবং পুনরাবৃত্তির ক্ষেত্রে ব্যবহারের ক্ষেত্রে হতে পারে। আমার মতে, এটি সহজতম পদ্ধতির। আপনি যদি তালিকায় স্থান পরিবর্তন করতে চান তবে এটি কোনওভাবেই "আসল" ফাংশনাল প্রোগ্রামিং হিসাবে বিবেচনা করা যায় না। তবে আপনি Collectors.partitioningBy()আপনার শর্ত পূরণ করে এমন উপাদানগুলির সাথে একটি নতুন তালিকা এবং যা না দেয় তাদের একটি নতুন তালিকা পাওয়ার জন্য আপনি ব্যবহার করতে পারেন । অবশ্যই এই পদ্ধতির সাথে, আপনার যদি শর্তটি সন্তুষ্টকারী একাধিক উপাদান থাকে তবে সেগুলি সমস্তই তালিকায় থাকবে এবং কেবল প্রথম নয়।


স্ট্রিম ফিল্টার করার জন্য এবং নতুন তালিকায় ফলাফল সংগ্রহ করা আরও ভাল
fps

1

নীচের যুক্তিটি মূল তালিকাটি পরিবর্তন না করেই সমাধান

List<String> str1 = new ArrayList<String>();
str1.add("A");
str1.add("B");
str1.add("C");
str1.add("D");

List<String> str2 = new ArrayList<String>();
str2.add("D");
str2.add("E");

List<String> str3 = str1.stream()
                        .filter(item -> !str2.contains(item))
                        .collect(Collectors.toList());

str1 // ["A", "B", "C", "D"]
str2 // ["D", "E"]
str3 // ["A", "B", "C"]

0

আমার প্রাথমিক ধারণা এবং আপনার উত্তরগুলির সংমিশ্রণে আমি পৌঁছেছি যা আমার নিজের প্রশ্নের সমাধান বলে মনে হচ্ছে:

public ProducerDTO findAndRemove(String pod) {
    ProducerDTO p = null;
    try {
        p = IntStream.range(0, producersProcedureActive.size())
             .filter(i -> producersProcedureActive.get(i).getPod().equals(pod))
             .boxed()
             .findFirst()
             .map(i -> producersProcedureActive.remove((int)i))
             .get();
        logger.debug(p);
    } catch (NoSuchElementException e) {
        logger.error("No producer found with POD [" + pod + "]");
    }
    return p;
}

এটি সেই বস্তুটি ব্যবহার করে সরিয়ে ফেলতে দেয় remove(int)যা পুনরায় তালিকায় প্রবেশ করবে না (@ টুনাকির পরামর্শ অনুসারে) এবং এটি মুছে ফেলা বস্তুকে ফাংশন ফিরিয়ে দেয়।

আমি আপনার উত্তরগুলি পড়েছি যা আমাকে ifPresentতার পরিবর্তে নিরাপদ পদ্ধতি বেছে নেওয়ার পরামর্শ দেয়get তবে আমি এই দৃশ্যে সেগুলি ব্যবহারের কোনও উপায় পাই না।

এই জাতীয় সমাধানের ক্ষেত্রে কোনও গুরুত্বপূর্ণ ত্রুটি রয়েছে?

হোলার পরামর্শ অনুসরণ করে সম্পাদনা করুন

এটি আমার প্রয়োজন ফাংশন হওয়া উচিত

public ProducerDTO findAndRemove(String pod) {
    return IntStream.range(0, producersProcedureActive.size())
            .filter(i -> producersProcedureActive.get(i).getPod().equals(pod))      
            .boxed()                                                                
            .findFirst()
            .map(i -> producersProcedureActive.remove((int)i))
            .orElseGet(() -> {
                logger.error("No producer found with POD [" + pod + "]"); 
                return null; 
            });
}

4
getআপনার ব্যতিক্রম ব্যবহার করা উচিত নয় । এটি কেবল খারাপ শৈলীই নয় তবে এটি খারাপ অভিনয়ও করতে পারে। পরিষ্কার সমাধানটি আরও সহজ,return /* stream operation*/.findFirst() .map(i -> producersProcedureActive.remove((int)i)) .orElseGet(() -> { logger.error("No producer found with POD [" + pod + "]"); return null; });
হলগার

0

কাজটি হ'ল: ✶ এবং ✶ উপাদানটি তালিকা থেকে সরান

p.stream().collect( Collectors.collectingAndThen( Collector.of(
    ArrayDeque::new,
    (a, producer) -> {
      if( producer.getPod().equals( pod ) )
        a.addLast( producer );
    },
    (a1, a2) -> {
      return( a1 );
    },
    rslt -> rslt.pollFirst()
  ),
  (e) -> {
    if( e != null )
      p.remove( e );  // remove
    return( e );    // get
  } ) );
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.