java - على - حلقه while



جافا: إضافة عناصر إلى مجموعة أثناء التكرار (12)

IMHO الطريقة الأكثر أمانًا هي إنشاء مجموعة جديدة ، للتكرار على مجموعتك المحددة ، وإضافة كل عنصر في المجموعة الجديدة ، وإضافة عناصر إضافية حسب الحاجة في المجموعة الجديدة أيضًا ، وأخيرًا إعادة المجموعة الجديدة.

هل من الممكن إضافة عناصر إلى مجموعة أثناء التكرار فوقها؟

وبشكل أكثر تحديدًا ، أود التكرار أكثر من مجموعة ، وإذا كان أحد العناصر يلبي شرطًا معينًا ، فإني أريد إضافة بعض العناصر الأخرى إلى المجموعة ، وتأكد من تكرار هذه العناصر المضافة أيضًا. (أدرك أن هذا قد يؤدي إلى حلقة غير مدمرة ، لكنني متأكد من أنها لن تكون في حالتي.)

يقترح Java Tutorial من Sun هذا غير ممكن: "لاحظ أن Iterator.remove هو الطريقة الآمنة الوحيدة لتعديل مجموعة أثناء التكرار ؛ السلوك غير محدد إذا تم تعديل المجموعة الأساسية بأي طريقة أخرى أثناء التكرار قيد التقدم. "

لذلك إذا لم أتمكن من القيام بما أريد القيام به باستخدام المبرمجين ، ماذا تقترح أن أفعل؟


Answer #1

أنا أفضل لمعالجة المجموعات وظيفيا بدلا من تحورها في مكانها. هذا يتجنب هذا النوع من المشاكل تماما ، وكذلك القضايا المتشعبة وغيرها من مصادر الخلل الحادة.

لذلك ، سأقوم بتنفيذها مثل:

List<Thing> expand(List<Thing> inputs) {
    List<Thing> expanded = new ArrayList<Thing>();

    for (Thing thing : inputs) {
        expanded.add(thing);
        if (needsSomeMoreThings(thing)) {
            addMoreThingsTo(expanded);
        }
    }

    return expanded;
}

Answer #2

إلى جانب حل استخدام قائمة إضافية و addAll استدعاء لإدراج العناصر الجديدة بعد التكرار (على سبيل المثال الحل من قبل المستخدم نات) ، يمكنك أيضا استخدام المجموعات المتزامنة مثل CopyOnWriteArrayList .

يستخدم الأسلوب "أسلوب لقطة" "أداة لقطة" مرجع إلى حالة الصفيف عند النقطة التي تم إنشاء المكرر. لا تتغيّر هذه المصفوفة أبداً خلال عمر المُكرّر ، لذا فإن التداخل مستحيل ويُضمن المكّون ألا يرمي ConcurrentModificationException.

مع هذه المجموعة الخاصة (التي تُستخدم عادةً للوصول المتزامن) من الممكن التعامل مع القائمة الأساسية أثناء التكرار فوقها. ومع ذلك ، لن يعكس المكرر التغييرات.

هل هذا أفضل من الحل الآخر؟ ربما لا ، أنا لا أعرف النفقات العامة التي قدمتها نهج النسخ عند الكتابة.


Answer #3

استخدم ListIterator النحو التالي:

List<String> l = new ArrayList<>();
l.add("Foo");
ListIterator<String> iter = l.listIterator(l.size());
while(iter.hasPrevious()){
    String prev=iter.previous();
    if(true /*You condition here*/){
        iter.add("Bah");
        iter.add("Etc");
    }
}

المفتاح هو التكرار في ترتيب عكسي - ثم تظهر العناصر المضافة في التكرار التالي.


Answer #4

على الرغم من أنه لا يمكننا إضافة عناصر إلى نفس القائمة أثناء التكرار ، يمكننا استخدام FlatMap في Java 8 ، لإضافة عناصر جديدة إلى دفق. يمكن القيام بذلك على شرط. بعد ذلك يمكن معالجة البند المضافة.

في ما يلي مثال Java يوضح كيفية الإضافة إلى الكائن الجاري المستمر استنادًا إلى شرط يتم معالجته بعد ذلك بشرط:

List<Integer> intList = new ArrayList<>();
intList.add(1);
intList.add(2);
intList.add(3);

intList = intList.stream().flatMap(i -> {
    if (i == 2) return Stream.of(i, i * 10); // condition for adding the extra items
    return Stream.of(i);
}).map(i -> i + 1)
        .collect(Collectors.toList());

System.out.println(intList);

ناتج مثال اللعبة هو:

[2 ، 3 ، 21 ، 4]


Answer #5

في الواقع أنها سهلة إلى حد ما. مجرد التفكير في الطريقة المثلى. أعتقد أن الطريقة المثلى هي:

for (int i=0; i<list.size(); i++) {
   Level obj = list.get(i);

   //Here execute yr code that may add / or may not add new element(s)
   //...

   i=list.indexOf(obj);
}

يعمل المثال التالي بشكل مثالي في الحالة المنطقية - عندما لا تحتاج إلى تكرار العناصر الجديدة المضافة قبل عنصر التكرار. حول العناصر المضافة بعد عنصر التكرار - قد تحتاج إلى عدم تكرارها. في هذه الحالة ، عليك ببساطة إضافة / أو تمديد كائن yr بعلامة تشير إلى عدم تكرارها.



Answer #7

للامتحان لدينا قائمتين:

  public static void main(String[] args) {
        ArrayList a = new ArrayList(Arrays.asList(new String[]{"a1", "a2", "a3","a4", "a5"}));
        ArrayList b = new ArrayList(Arrays.asList(new String[]{"b1", "b2", "b3","b4", "b5"}));
        merge(a, b);
        a.stream().map( x -> x + " ").forEach(System.out::print);
    }
   public static void merge(List a, List b){
        for (Iterator itb = b.iterator(); itb.hasNext(); ){
            for (ListIterator it = a.listIterator() ; it.hasNext() ; ){
                it.next();
                it.add(itb.next());

            }
        }

    }

a1 b1 a2 b2 a3 b3 a4 b4 a5 b5


Answer #8

نسيان التكرارات ، فهي لا تعمل لإضافة ، فقط للإزالة. تنطبق إجابتي على القوائم فقط ، لذا لا تعاقبني لعدم حل المشكلة بالنسبة للمجموعات. التزم بالأساسيات:

    List<ZeObj> myList = new ArrayList<ZeObj>();
    // populate the list with whatever
            ........
    int noItems = myList.size();
    for (int i = 0; i < noItems; i++) {
        ZeObj currItem = myList.get(i);
        // when you want to add, simply add the new item at last and
        // increment the stop condition
        if (currItem.asksForMore()) {
            myList.add(new ZeObj());
            noItems++;
        }
    }

Answer #9

هذا ما أفعله عادةً ، مع مجموعات مثل المجموعات:

Set<T> adds = new HashSet<T>, dels = new HashSet<T>;
for ( T e: target )
  if ( <has to be removed> ) dels.add ( e );
  else if ( <has to be added> ) adds.add ( <new element> )

target.removeAll ( dels );
target.addAll ( adds );

وهذا يخلق بعض الذاكرة الإضافية (مؤشرات للمجموعات الوسيطة ، ولكن لا تحدث عناصر مكررة) وخطوات إضافية (تتكرر مرة أخرى على التغييرات) ، ولكن عادة ما لا تكون هذه صفقة كبيرة ، وقد يكون أفضل من العمل مع نسخة أولية من المجموعة.


Answer #10

بشكل عام ، إنها ليست آمنة ، على الرغم من أن بعض المجموعات قد تكون. البديل الواضح هو استخدام نوع من الحلقة. لكنك لم تقل ما هي المجموعة التي تستخدمها ، لذا قد يكون ذلك ممكنًا أو غير ممكن.


Answer #11
public static void main(String[] args)
{
    // This array list simulates source of your candidates for processing
    ArrayList<String> source = new ArrayList<String>();
    // This is the list where you actually keep all unprocessed candidates
    LinkedList<String> list = new LinkedList<String>();

    // Here we add few elements into our simulated source of candidates
    // just to have something to work with
    source.add("first element");
    source.add("second element");
    source.add("third element");
    source.add("fourth element");
    source.add("The Fifth Element"); // aka Milla Jovovich

    // Add first candidate for processing into our main list
    list.addLast(source.get(0));

    // This is just here so we don't have to have helper index variable
    // to go through source elements
    source.remove(0);

    // We will do this until there are no more candidates for processing
    while(!list.isEmpty())
    {
        // This is how we get next element for processing from our list
        // of candidates. Here our candidate is String, in your case it
        // will be whatever you work with.
        String element = list.pollFirst();
        // This is where we process the element, just print it out in this case
        System.out.println(element);

        // This is simulation of process of adding new candidates for processing
        // into our list during this iteration.
        if(source.size() > 0) // When simulated source of candidates dries out, we stop
        {
            // Here you will somehow get your new candidate for processing
            // In this case we just get it from our simulation source of candidates.
            String newCandidate = source.get(0);
            // This is the way to add new elements to your list of candidates for processing
            list.addLast(newCandidate);
            // In this example we add one candidate per while loop iteration and 
            // zero candidates when source list dries out. In real life you may happen
            // to add more than one candidate here:
            // list.addLast(newCandidate2);
            // list.addLast(newCandidate3);
            // etc.

            // This is here so we don't have to use helper index variable for iteration
            // through source.
            source.remove(0);
        }
    }
}




iterator