কোনও লুপে অবজেক্টগুলি সরিয়ে রাখার সময় কোনও সংগ্রহের মাধ্যমে আইট্রেট করা, সমকালীন মডেলিংএক্সেপশন এড়ানো


1194

আমরা সবাই জানি যে কারণে আপনি নিম্নলিখিতটি করতে পারবেন না ConcurrentModificationException:

for (Object i : l) {
    if (condition(i)) {
        l.remove(i);
    }
}

তবে এটি দৃশ্যত কখনও কখনও কাজ করে তবে সবসময় না। এখানে কিছু নির্দিষ্ট কোড রয়েছে:

public static void main(String[] args) {
    Collection<Integer> l = new ArrayList<>();

    for (int i = 0; i < 10; ++i) {
        l.add(4);
        l.add(5);
        l.add(6);
    }

    for (int i : l) {
        if (i == 5) {
            l.remove(i);
        }
    }

    System.out.println(l);
}

এটি অবশ্যই ফলাফল:

Exception in thread "main" java.util.ConcurrentModificationException

যদিও একাধিক থ্রেড এটি করছে না। যাই হোক।

এই সমস্যার সর্বোত্তম সমাধান কি? এই ব্যতিক্রমটি না ছুঁড়ে আমি কীভাবে সংগ্রহ থেকে কোনও লুপে কোনও আইটেম সরিয়ে ফেলতে পারি?

আমি Collectionএখানেও একটি স্বেচ্ছাচারিতা ব্যবহার করছি , অগত্যা একটি নয় ArrayList, যাতে আপনি নির্ভর করতে পারবেন না get


পাঠকদের জন্য দ্রষ্টব্য: ডকস.অরাকল . com / javase / tutorial / collections / interfaces / … পড়ুন , আপনি যা করতে চান তা অর্জন করার এটির সহজ উপায় হতে পারে।
GKFX

উত্তর:


1601

Iterator.remove() নিরাপদ, আপনি এটি এটি ব্যবহার করতে পারেন:

List<String> list = new ArrayList<>();

// This is a clever way to create the iterator and call iterator.hasNext() like
// you would do in a while-loop. It would be the same as doing:
//     Iterator<String> iterator = list.iterator();
//     while (iterator.hasNext()) {
for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
    String string = iterator.next();
    if (string.isEmpty()) {
        // Remove the current element from the iterator and the list.
        iterator.remove();
    }
}

দ্রষ্টব্য যে Iterator.remove()পুনরাবৃত্তির সময় কোনও সংকলন পরিবর্তন করার একমাত্র নিরাপদ উপায়; পুনরাবৃত্তির অগ্রগতি চলাকালীন যদি অন্তর্নিহিত সংগ্রহটি অন্য কোনও উপায়ে সংশোধন করা হয় তবে আচরণটি অনির্দিষ্ট ।

উত্স: docs.oracle> সংগ্রহ ইন্টারফেস


এবং একইভাবে, আপনার যদি একটি থাকে ListIteratorএবং আইটেমগুলি যুক্ত করতে চান তবে আপনি ListIterator#addএকই কারণে আপনি ব্যবহার করতে পারেন Iterator#remove - এটি এটির অনুমতি দেওয়ার জন্য ডিজাইন করা হয়েছে।


আপনার ক্ষেত্রে আপনি একটি তালিকা থেকে সরিয়ে ফেলার চেষ্টা করেছেন, তবে এর বিষয়বস্তুটি পুনরাবৃত্তি করার সময় যদি চেষ্টা করার চেষ্টা করা putহয় তবে একই বিধিনিষেধটি প্রযোজ্য Map


19
আপনি যদি বর্তমান পুনরাবৃত্তিতে ফিরে আসা উপাদান ব্যতীত অন্য কোনও উপাদান সরিয়ে নিতে চান?
ইউজেন

2
আপনাকে পুনরাবৃত্তিতে .reove ব্যবহার করতে হবে এবং এটি কেবলমাত্র বর্তমান উপাদানটি সরাতে সক্ষম, তাই না :)
বিল কে

1
কনক্র্যান্টলিঙ্কডডিক বা কপিঅনওয়াইরাইটআরলিলিস্ট ব্যবহার করার সাথে তুলনায় এটি ধীর গতির (কমপক্ষে আমার ক্ষেত্রে)
ড্যান

1
iterator.next()কলটি অন-লুপে রাখা কি সম্ভব নয় ? তা না হলে কেউ ব্যাখ্যা করতে পারেন কেন?
ব্লেক

1
@ গোনেনআই এটি সংগ্রহ থেকে সমস্ত পুনরাবৃত্তকারীদের জন্য বাস্তবায়িত হয় যা স্থাবর নয়। List.addএকই অর্থে "alচ্ছিক", তবে আপনি কোনও তালিকায় যুক্ত করা "অনিরাপদ" বলবেন না।
রেডিওডেফ

345

এইটা কাজ করে:

Iterator<Integer> iter = l.iterator();
while (iter.hasNext()) {
    if (iter.next() == 5) {
        iter.remove();
    }
}

আমি ধরে নিয়েছি যেহেতু ফোরচ লুপটি পুনরাবৃত্তির জন্য সিনট্যাকটিক চিনি, তাই একটি পুনরুক্তি ব্যবহারকারীর সাহায্য করবে না ... তবে এটি আপনাকে এই .remove()কার্যকারিতা দেয় ।


43
foreach লুপ পুনরাবৃত্তি জন্য সিনট্যাকটিক চিনি হয়। তবে আপনি যেমনটি উল্লেখ করেছেন, আপনাকে পুনরাবৃত্তকারীকে অপসারণ কল করতে হবে - যা পূর্বাভাস আপনাকে অ্যাক্সেস দেয় না। অত: পর যে কারণে আপনি একটি foreach লুপ সরাতে পারবেন না (যদিও আপনি হয় আসলে অধীনে ফণা কোনো ইটারেটরে ব্যবহার করে)
madlep

36
এটির ব্যবহারের জন্য কোডের উদাহরণস্বরূপ +1 সরু () প্রসঙ্গে, যা কে কে এর উত্তর [সরাসরি] দেয় না।
এডিট

202

জাভা 8 এর সাহায্যে আপনি নতুন removeIfপদ্ধতিটি ব্যবহার করতে পারেন । আপনার উদাহরণ প্রয়োগ করা:

Collection<Integer> coll = new ArrayList<>();
//populate

coll.removeIf(i -> i == 5);

3
Ooooo! আমি আশা করছিলাম জাভা 8 বা 9 তে কিছু সাহায্য করবে। এটি এখনও আমার কাছে ভার্জোজ মনে হয় তবে আমি এখনও এটি পছন্দ করি।
জেমস টি স্টেল

এই ক্ষেত্রেও সমান () প্রয়োগের প্রস্তাব দেওয়া হচ্ছে?
আনমল গুপ্ত

প্রণালী দ্বারা removeIfব্যবহারসমূহ Iteratorএবং whileলুপ। আপনি এটি জাভা 8java.util.Collection.java
omehakanbilici

3
@ উমরহাকানবিলিচি কিছু বাস্তবায়ন যেমন ArrayListপারফরম্যান্সের কারণে ওভাররাইড করে আপনি যার সাথে উল্লেখ করছেন সেটি হ'ল ডিফল্ট বাস্তবায়ন।
দিদিয়ের এল

@ আনমলগুপ্ত: না, equalsএখানে মোটেই ব্যবহৃত হয় না, সুতরাং এটি প্রয়োগ করা হবে না। (তবে অবশ্যই, আপনি equalsযদি নিজের পরীক্ষায় ব্যবহার করেন তবে এটি যেভাবে চান তেমন প্রয়োগ করতে হবে))
লিই

42

যেহেতু প্রশ্নের ইতিমধ্যে উত্তর দেওয়া হয়েছে অর্থাৎ সবচেয়ে ভাল উপায় হ'ল পুনরাবৃত্তিকারী অবজেক্টের অপসারণ পদ্ধতিটি ব্যবহার করা, আমি ত্রুটিটি যেখানে ফেলেছি সেখানকার স্পেসিফিকেশনে যেতে চাই "java.util.ConcurrentModificationException"

প্রতিটি সংগ্রহ বর্গ একটি প্রাইভেট বর্গ যা ইটারেটর ইন্টারফেস প্রয়োগ মত পদ্ধতি প্রদান করে next(), remove()এবং hasNext()

পরবর্তী কোডটি এরকম কিছু দেখায় ...

public E next() {
    checkForComodification();
    try {
        E next = get(cursor);
        lastRet = cursor++;
        return next;
    } catch(IndexOutOfBoundsException e) {
        checkForComodification();
        throw new NoSuchElementException();
    }
}

এখানে পদ্ধতি checkForComodificationহিসাবে বাস্তবায়ন করা হয়

final void checkForComodification() {
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
}

সুতরাং, আপনি যেমন দেখতে পাচ্ছেন, আপনি যদি সংগ্রহ থেকে কোনও উপাদান সরিয়ে দেওয়ার চেষ্টা করেন। এটির modCountথেকে পৃথক হওয়ার expectedModCountফলস্বরূপ ব্যতিক্রম হয় ConcurrentModificationException


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

26

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

public static void main(String[] args)
{
    Collection<Integer> l = new ArrayList<Integer>();
    Collection<Integer> itemsToRemove = new ArrayList<>();
    for (int i=0; i < 10; i++) {
        l.add(Integer.of(4));
        l.add(Integer.of(5));
        l.add(Integer.of(6));
    }
    for (Integer i : l)
    {
        if (i.intValue() == 5) {
            itemsToRemove.add(i);
        }
    }

    l.removeAll(itemsToRemove);
    System.out.println(l);
}

7
আমি সাধারনত এটিই করি তবে স্পষ্টত পুনরাবৃত্তি হ'ল আমি মনে করি আরও এলিগ্যান্ট সমাধান।
ক্লাদিউ

1
যথেষ্ট পরিমাণে ন্যায়সঙ্গত, যতক্ষণ না আপনি পুনরুক্তিকারীর সাথে অন্য কিছু করছেন না - এটি প্রকাশিত হওয়ার ফলে কল প্রতিরোধের মতো কাজ করা সহজ হয় ne এনেক্সট () প্রতি লুপে দুবার ইত্যাদি a কোনও বিশাল সমস্যা নয়, তবে সমস্যাগুলি তৈরি করতে পারে যদি আপনি করছেন এন্ট্রি মোছার জন্য কেবলমাত্র কোনও তালিকা চালানো ছাড়া আরও জটিল কিছু।
রোডিও ক্লাউন

@ রোডিও ক্লাউন: মূল প্রশ্নে, ক্লডিউ পুনরুক্তিকারীকে নয়, সংগ্রহ থেকে সরিয়ে ফেলছে।
ম্যাট বি

1
পুনরাবৃত্তকারী থেকে অপসারণ অন্তর্নিহিত সংগ্রহ থেকে সরিয়ে দেয় ... তবে আমি শেষ মন্তব্যে যা বলছিলাম তা হ'ল যদি আপনি পুনরুক্তিগুলি (সঠিক তথ্য প্রক্রিয়াকরণের মতো) পুনরুক্তি ব্যবহার করে কেবল আরও জটিল কিছু করছেন তবে কিছু তৈরি করতে পারেন ত্রুটি করা সহজ।
রোডিও ক্লাউন 18

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

17

এই জাতীয় ক্ষেত্রে পিছনে পিছনে যেতে একটি সাধারণ কৌশল (ছিল?):

for(int i = l.size() - 1; i >= 0; i --) {
  if (l.get(i) == 5) {
    l.remove(i);
  }
}

এটি বলেছিল, আমি জাভা 8, যেমন removeIfবা filterস্ট্রিমগুলিতে আপনার আরও ভাল উপায় পেয়েছি বলে আমি বেশি খুশি ।


2
এটি একটি ভাল কৌশল। তবে এটি সেটগুলির মতো অ-সূচকযুক্ত সংগ্রহগুলিতে কাজ করবে না এবং লিঙ্কযুক্ত তালিকাগুলি বলায় এটি ধীর হবে।
ক্লাদিউ

@ ক্লডিউ হ্যাঁ, এটি অবশ্যই কেবলমাত্র ArrayListএস বা অনুরূপ সংগ্রহের জন্য।
ল্যান্ডেই

আমি একটি অ্যারেলিস্ট ব্যবহার করছি, এটি পুরোপুরি কাজ করেছে, ধন্যবাদ।
স্টারসুইপার

2
সূচকগুলি দুর্দান্ত। যদি এটি এত সাধারণ হয় তবে আপনি কেন ব্যবহার করবেন না for(int i = l.size(); i-->0;) {?
জন


12

সঙ্গে অন্ধকার সংগ্রহগুলি , পদ্ধতি removeIfসংজ্ঞাসমূহ MutableCollection কাজ করবে:

MutableList<Integer> list = Lists.mutable.of(1, 2, 3, 4, 5);
list.removeIf(Predicates.lessThan(3));
Assert.assertEquals(Lists.mutable.of(3, 4, 5), list);

জাভা 8 লাম্বদা সিনট্যাক্স সহ এটি নিম্নরূপ লেখা যেতে পারে:

MutableList<Integer> list = Lists.mutable.of(1, 2, 3, 4, 5);
list.removeIf(Predicates.cast(integer -> integer < 3));
Assert.assertEquals(Lists.mutable.of(3, 4, 5), list);

কলটি Predicates.cast()এখানে প্রয়োজনীয় কারণ জাভা 8 এর ইন্টারফেসে একটি ডিফল্ট removeIfপদ্ধতি যুক্ত করা হয়েছিল java.util.Collection

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


10

বিদ্যমান তালিকার একটি অনুলিপি তৈরি করুন এবং নতুন অনুলিপিটির মাধ্যমে পুনরাবৃত্তি করুন।

for (String str : new ArrayList<String>(listOfStr))     
{
    listOfStr.remove(/* object reference or index */);
}

19
অনুলিপি তৈরি করা সম্পদের অপচয় হিসাবে মনে হচ্ছে sounds
আন্তজি

3
@ আন্টজি যা তালিকার আকার এবং এর মধ্যে থাকা বস্তুর ঘনত্বের উপর নির্ভর করে। এখনও একটি মূল্যবান এবং কার্যকর সমাধান।
মের 14

আমি এই পদ্ধতি ব্যবহার করা হয়। এটি কিছুটা বেশি সংস্থান লাগে তবে আরও নমনীয় এবং স্পষ্ট clear
তাও ঝাং

আপনি যখন লুপের ভিতরে থাকা বস্তুগুলি সরিয়ে ফেলতে চাইছেন না তখন এটি একটি ভাল সমাধান, তবে তারা অন্য থ্রেডগুলি (যেমন নেটওয়ার্ক অপারেশন আপডেট করার ডেটা) থেকে "এলোমেলোভাবে" সরানো হয়। আপনি যদি নিজেকে এই অনুলিপিগুলি খুব বেশি করে দেখতে পান তবে একটি জাভা বাস্তবায়নও ঠিক এইভাবে করছে: ডকস.ওরাকল.com
জাভাসে

8

লোকেরা জোর দিয়ে বলছে যে কোনও ফোরচ লুপ দ্বারা পুনরাবৃত্তি হওয়া সংগ্রহ থেকে এটি সরানো যাবে না । আমি কেবল এটি প্রযুক্তিগতভাবে ভুল এবং সঠিকভাবে বর্ণনা করতে চেয়েছিলাম (আমি জানি ওপির প্রশ্নটি এতটা উন্নত যে এটি জানতে পেরে উঠতে পারে ) এই অনুমানের পিছনের কোডটি:

for (TouchableObj obj : untouchedSet) {  // <--- This is where ConcurrentModificationException strikes
    if (obj.isTouched()) {
        untouchedSet.remove(obj);
        touchedSt.add(obj);
        break;  // this is key to avoiding returning to the foreach
    }
}

এটি এমন নয় যে আপনি পুনরাবৃত্তি থেকে সরাতে পারবেন না Colletionবরং আপনি একবার করার পরে পুনরাবৃত্তি চালিয়ে যেতে পারবেন না। সুতরাং breakউপরের কোডে।

এই উত্তরটি যদি কিছুটা বিশেষজ্ঞের ব্যবহারের ক্ষেত্রে হয় এবং মূল থ্রেড থেকে আমি এখানে পৌঁছেছি তার চেয়ে বেশি উপযুক্ত, তবে এটির একটি সদৃশ হিসাবে চিহ্নিত করা হয়েছে (এই থ্রেডটি আরও স্নিগ্ধভাবে প্রদর্শিত হওয়া সত্ত্বেও) এটি লক হয়ে গেছে।


8

লুপ জন্য একটি traditionalতিহ্যগত সঙ্গে

ArrayList<String> myArray = new ArrayList<>();

for (int i = 0; i < myArray.size(); ) {
    String text = myArray.get(i);
    if (someCondition(text))
        myArray.remove(i);
    else
        i++;   
}

আহ, সুতরাং এটি কেবলমাত্র বর্ধিত -লুপ যা ব্যতিক্রম ছোঁড়ে।
cellepo

এফডাব্লুআইডাব্লু - একই কোডটি i++লুপ বডির পরিবর্তে লুপ গার্ডে ইনক্রিমেন্টে পরিবর্তন করার পরেও কাজ করবে ।
cellepo

সংশোধন That: এটি হ'ল যদি i++ইনক্রিমেন্টিং শর্তসাপেক্ষ না হয় - আমি এখন দেখি যে এটি আপনি শরীরে করছেন :)
cellepo

2

ListIteratorআপনাকে তালিকার আইটেমগুলি যুক্ত বা সরাতে দেয়। ধরুন আপনার কাছে Carঅবজেক্টের একটি তালিকা রয়েছে :

List<Car> cars = ArrayList<>();
// add cars here...

for (ListIterator<Car> carIterator = cars.listIterator();  carIterator.hasNext(); )
{
   if (<some-condition>)
   { 
      carIterator().remove()
   }
   else if (<some-other-condition>)
   { 
      carIterator().add(aNewCar);
   }
}

তালিকালীন ইন্টারফেসের অতিরিক্ত পদ্ধতি ( আইট্রেটারের সম্প্রসারণ) আকর্ষণীয় - বিশেষত এর previousপদ্ধতি।
cellepo

1

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

//"list" is ArrayList<Object>
//"state" is some boolean variable, which when set to true, Object will be removed from the list
int index = 0;
while(index < list.size()) {
    Object r = list.get(index);
    if( state ) {
        list.remove(index);
        index = 0;
        continue;
    }
    index += 1;
}

এটি কনকুরেন্সি ব্যতিক্রম এড়ানো হবে।


1
প্রশ্ন স্পষ্টতই বলেছে যে ওপি ব্যবহারের প্রয়োজন নেই ArrayListএবং সুতরাং নির্ভর করতে পারে না get()। অন্যথায় সম্ভবত একটি ভাল পদ্ধতির, যদিও।
ক্যাসক্লোটি

(স্পষ্টকরণ ^) ওপি একটি স্বেচ্ছাচারিতা ব্যবহার করছে Collection- Collectionইন্টারফেস অন্তর্ভুক্ত নয় get। (যদিও এফডাব্লুআইডাব্লু Listইন্টারফেসের মধ্যে 'get' অন্তর্ভুক্ত রয়েছে)।
cellepo

আমি এখানে একটি পৃথক, আরও বিশদ উত্তর যুক্ত করেছি - while-লুপিংয়ের জন্যও List। তবে এই উত্তরের জন্য +1 কারণ এটি প্রথম এসেছে।
cellepo

1

ConcurrentHashMap বা ConcurrentLinkedQueue বা ConcurrentSkipListMap আরেকটি বিকল্প হতে পারে, কারণ তারা কোনো ConcurrentModificationException নিক্ষেপ করবে না, এমনকি যদি আপনি সরাতে অথবা আইটেমের যোগ করুন।


হ্যাঁ, এবং দ্রষ্টব্য যে সেগুলি সমস্ত java.util.concurrentপ্যাকেজে রয়েছে। সেই প্যাকেজটির অন্যান্য কিছু অনুরূপ / সাধারণ-ব্যবহারের ক্ষেত্রে ক্লাসগুলি CopyOnWriteArrayList & CopyOnWriteArraySet [তবে তাদের মধ্যে সীমাবদ্ধ নয়)।
cellepo

প্রকৃতপক্ষে, আমি কেবল শিখেছি যে যদিও সেই ডেটা স্ট্রাকচার অবজেক্টগুলি এড়ানো যায় ConcurrentModificationException , বর্ধিত -লুপে এগুলি ব্যবহার করা তবুও IndexOutOfBoundsException
সূচিকরণের

1

আমি জানি এই প্রশ্নটি জাভা 8 সম্পর্কে খুব পুরানো, তবে জাভা 8 ব্যবহারকারীদের জন্য আপনি সহজেই অপসারণ ব্যবহার করতে পারেন ():

Collection<Integer> l = new ArrayList<Integer>();

for (int i=0; i < 10; ++i) {
    l.add(new Integer(4));
    l.add(new Integer(5));
    l.add(new Integer(6));
}

l.removeIf(i -> i.intValue() == 5);

1

অন্য উপায়টি হ'ল আপনার অ্যারেলিস্টের একটি অনুলিপি তৈরি করুন:

List<Object> l = ...

List<Object> iterationList = ImmutableList.copyOf(l);

for (Object i : iterationList) {
    if (condition(i)) {
        l.remove(i);
    }
}

দ্রষ্টব্য: বস্তুর পরিবর্তে iএকটি indexনয়। সম্ভবত এটি কল objকরা আরও উপযুক্ত হবে।
ভাগ্যোডোনাল্ড

1

সেরা উপায় (প্রস্তাবিত) হল java.util.Concurrent প্যাকেজ ব্যবহার। এই প্যাকেজটি ব্যবহার করে আপনি সহজেই এই ব্যতিক্রমটি এড়াতে পারবেন। পরিবর্তিত কোড উল্লেখ করুন

public static void main(String[] args) {
    Collection<Integer> l = new CopyOnWriteArrayList<Integer>();

    for (int i=0; i < 10; ++i) {
        l.add(new Integer(4));
        l.add(new Integer(5));
        l.add(new Integer(6));
    }

    for (Integer i : l) {
        if (i.intValue() == 5) {
            l.remove(i);
        }
    }

    System.out.println(l);
}

0

অ্যারেলিস্টের ক্ষেত্রে : মুছে ফেলুন (ইনটেক্স ইনডেক্স) - যদি (সূচকটি শেষ উপাদানটির অবস্থান হয়) এটি ছাড়া এড়ানো System.arraycopy()এবং এর জন্য সময় নেয় না।

অ্যারেকপির সময় বাড়লে যদি (সূচক হ্রাস হয়), তবে তালিকার উপাদানগুলিও হ্রাস পায়!

সর্বোত্তম কার্যকর অপসারণের উপায় হ'ল: উত্পন্ন ক্রমে এর উপাদানগুলি সরিয়ে ফেলা: while(list.size()>0)list.remove(list.size()-1);// লাগে ও (1) while(list.size()>0)list.remove(0);// লাগে ও (ফ্যাকটোরিয়াল (এন)) নেয়

//region prepare data
ArrayList<Integer> ints = new ArrayList<Integer>();
ArrayList<Integer> toRemove = new ArrayList<Integer>();
Random rdm = new Random();
long millis;
for (int i = 0; i < 100000; i++) {
    Integer integer = rdm.nextInt();
    ints.add(integer);
}
ArrayList<Integer> intsForIndex = new ArrayList<Integer>(ints);
ArrayList<Integer> intsDescIndex = new ArrayList<Integer>(ints);
ArrayList<Integer> intsIterator = new ArrayList<Integer>(ints);
//endregion

// region for index
millis = System.currentTimeMillis();
for (int i = 0; i < intsForIndex.size(); i++) 
   if (intsForIndex.get(i) % 2 == 0) intsForIndex.remove(i--);
System.out.println(System.currentTimeMillis() - millis);
// endregion

// region for index desc
millis = System.currentTimeMillis();
for (int i = intsDescIndex.size() - 1; i >= 0; i--) 
   if (intsDescIndex.get(i) % 2 == 0) intsDescIndex.remove(i);
System.out.println(System.currentTimeMillis() - millis);
//endregion

// region iterator
millis = System.currentTimeMillis();
for (Iterator<Integer> iterator = intsIterator.iterator(); iterator.hasNext(); )
    if (iterator.next() % 2 == 0) iterator.remove();
System.out.println(System.currentTimeMillis() - millis);
//endregion
  • সূচক লুপের জন্য: 1090 ম্যাসি
  • ডেস্ক সূচক জন্য: 519 এমসিকি --- সেরা
  • পুনরুক্তকারীর জন্য: 1043 ম্যাসি

0
for (Integer i : l)
{
    if (i.intValue() == 5){
            itemsToRemove.add(i);
            break;
    }
}

তালিকাটি থেকে উপাদানটি সরিয়ে ফেলার পরে ক্যাচটি হ'ল যদি আপনি অভ্যন্তরীণ পুনরাবৃত্তকারী.নেক্সট () কলটি এড়িয়ে যান। এটি এখনও কাজ করে! যদিও আমি কোডটি এভাবে লেখার প্রস্তাব দিই না এটি এর পিছনের ধারণাটি বুঝতে সহায়তা করে :-)

চিয়ার্স!


0

থ্রেড নিরাপদ সংগ্রহের পরিবর্তনের উদাহরণ:

public class Example {
    private final List<String> queue = Collections.synchronizedList(new ArrayList<String>());

    public void removeFromQueue() {
        synchronized (queue) {
            Iterator<String> iterator = queue.iterator();
            String string = iterator.next();
            if (string.isEmpty()) {
                iterator.remove();
            }
        }
    }
}

0

আমি জানি এই প্রশ্নটি কেবল একটি হিসাবে ধরেছে Collection, আরও নির্দিষ্টভাবে কোনও নয় List। তবে যারা এই প্রশ্নটি পড়ছেন যারা প্রকৃতপক্ষে একটি Listরেফারেন্স নিয়ে কাজ করছেন , আপনি যদি এড়াতে চানConcurrentModificationExceptionwhileIterator তবে (যদি আপনি এটি সাধারণভাবে এড়াতে চান, অথবা এটি অর্জনে বিশেষত এড়াতে চান) তবে আপনি একটি লুপ দিয়ে এড়াতে পারবেন প্রতিটি উপাদান থেকে শুরু থেকে শেষের দিকে থামানো থেকে পৃথক একটি লুপিং ক্রম [যা আমি বিশ্বাস করি এটিই কেবল আদেশIterator আদেশই করতে পারে]]:

* আপডেট: নীচে মন্তব্যগুলি দেখুন যে স্পষ্ট করে অ্যানালোগুলিটি প্রচলিত -লুপের সাথেও অর্জনযোগ্য ।

final List<Integer> list = new ArrayList<>();
for(int i = 0; i < 10; ++i){
    list.add(i);
}

int i = 1;
while(i < list.size()){
    if(list.get(i) % 2 == 0){
        list.remove(i++);

    } else {
        i += 2;
    }
}

এই কোড থেকে কোনও সমকালীন মডিফিকেশনএক্সসেপশন নেই।

সেখানে আমরা দেখছি লুপিং শুরুতে শুরু হয় না, এবং প্রতিটি উপাদানগুলিতে থামে না (যা আমি বিশ্বাস করি)Iterator নিজে করতে পারে না)।

FWIW আমরা আরও দেখুন getআহ্বান করা হচ্ছে list, যা সম্পন্ন করা যায়নি যদি তার রেফারেন্স ঠিক ছিল Collection(আরও নির্দিষ্ট পরিবর্তে Listএর টাইপ Collection) - Listইন্টারফেস অন্তর্ভুক্ত get, কিন্তু Collectionইন্টারফেস না। যদি সেই পার্থক্যের জন্য না হয় তবে তারপরে listরেফারেন্সটি হ'ল Collection[এবং সুতরাং প্রযুক্তিগতভাবে এই উত্তরটি তখন স্পর্শকাতর উত্তরের পরিবর্তে সরাসরি উত্তর হবে]।

এফডব্লিউআইডাব্লুডাব্লু একই কোডটি এখনও প্রতিটি উপাদানের স্টপ শুরুতে শুরু করার জন্য সংশোধিত হওয়ার পরেও কাজ করে (ঠিক একইভাবে Iterator):

final List<Integer> list = new ArrayList<>();
for(int i = 0; i < 10; ++i){
    list.add(i);
}

int i = 0;
while(i < list.size()){
    if(list.get(i) % 2 == 0){
        list.remove(i);

    } else {
        ++i;
    }
}

তবে এটি অপসারণ করতে এখনও সূচীর খুব সতর্কতার সাথে গণনা প্রয়োজন।
ওয়ানক্রিটের ডিসি

এছাড়াও, এই এই উত্তর শুধু একটি আরো বিস্তারিত ব্যাখ্যা stackoverflow.com/a/43441822/2308683
OneCricketeer

জেনে রাখা ভাল - ধন্যবাদ! যে অন্যান্য উত্তর আমাকে বুঝতে এটাই সাহায্য করেছে উন্নত -for-লুপ যে নিক্ষেপ করা হবে ConcurrentModificationException, কিন্তু না ঐতিহ্যগত -for-লুপ (যা অন্যান্য উত্তর ব্যবহার করে) - যে আগে বুঝতে না কেন আমি এই উত্তর লিখতে প্রেরণা হয়েছিল (ভুল আমি তারপর চিন্তা যে এটি ছিল সব জন্য-লুপ যে ব্যতিক্রম নিক্ষেপ হবে)।
cellepo

0

একটি সমাধান হ'ল তালিকাটি ঘোরানো এবং কনকেনারমোডিশনএক্সেপশন বা সূচিপত্রের বাইরে থাকা এড়াতে প্রথম উপাদানটি সরিয়ে ফেলতে হবে

int n = list.size();
for(int j=0;j<n;j++){
    //you can also put a condition before remove
    list.remove(0);
    Collections.rotate(list, 1);
}
Collections.rotate(list, -1);

0

এটি ব্যবহার করে দেখুন (তালিকার সমস্ত উপাদান সমান হবে i):

for (Object i : l) {
    if (condition(i)) {
        l = (l.stream().filter((a) -> a != i)).collect(Collectors.toList());
    }
}

-2

এটি সেরা উপায় নাও হতে পারে তবে বেশিরভাগ ছোট ক্ষেত্রে এটি গ্রহণযোগ্য হওয়া উচিত:

"দ্বিতীয় খালি অ্যারে তৈরি করুন এবং কেবল আপনি রাখতে চান এটি যুক্ত করুন"

আমি কোথা থেকে এটি পড়েছি তা মনে নেই ... ন্যায়বিচারের জন্য আমি এই উইকিটিকে আশায় তৈরি করব যে কেউ এটি খুঁজে পেয়েছে বা কেবল উপার্জনযোগ্য নয় তার জন্য উপার্জনযোগ্য নয়।

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