wake-up-neo.com

Ändern jedes Elements einer Liste in Java

Ich fange gerade an, mit Listen in Java zu arbeiten. Ich frage mich, welche Methode empfohlen wird, um jedes Element einer Liste zu ändern.

Ich habe es mit beiden folgenden Methoden geschafft, aber beide scheinen ziemlich unelegant zu sein. Gibt es einen besseren Weg, dies in Java zu erreichen? Und wird eine der folgenden Methoden über die andere empfohlen oder sind beide auf derselben Ebene?

//Modifying with foreach
for (String each : list)
{
    list.set(list.indexOf(each), each+ " blah");
}

//Modifying with for
for (ListIterator<String> i = list.listIterator(); i.hasNext(); i.next()) 
{
    i.next();
    list.set(i.nextIndex()-1, i.previous() + " blah yadda");
}
17
Shisa

Die zweite Version wäre besser. Intern sind sie am Ende gleich, aber beim zweiten können Sie die Liste ändern, während beim ersten eine ConcurrentModificationException ausgelöst wird.

Aber dann benutzt du den Iterator falsch. So machen Sie es richtig:

for (final ListIterator<String> i = list.listIterator(); i.hasNext();) {
  final String element = i.next();
  i.set(element + "yaddayadda");
}

Der Iterator ist derjenige, der die Liste ändern muss, da er der einzige ist, der weiß, wie man das richtig macht, ohne sich über die Listenelemente und die Reihenfolge zu verwirren.

Edit: Weil ich das in allen Kommentaren und den anderen Antworten sehe:

Warum sollten Sie list.get, list.set und list.size nicht in einer Schleife verwenden

Das Java-Collections-Framework enthält viele Sammlungen, die jeweils für bestimmte Anforderungen optimiert sind. Viele Leute verwenden die ArrayList, die intern ein Array verwendet. Dies ist in Ordnung, solange sich die Anzahl der Elemente im Laufe der Zeit nicht wesentlich ändert und der besondere Vorteil besteht, dass get, set und size konstante Zeitoperationen für diesen bestimmten Listentyp sind.

Es gibt jedoch andere Listentypen, bei denen dies nicht zutrifft. Wenn Sie beispielsweise über eine Liste verfügen, die ständig wächst und/oder schrumpft, ist es viel besser, eine LinkedList zu verwenden, da das Hinzufügen (Element) im Gegensatz zu ArrayList eine konstante Zeitoperation ist, aber Hinzufügen (Index, Element), index) und entfernen (index) sind nicht!  

Um die Position des bestimmten Indexes zu ermitteln, muss die Liste vom ersten/letzten durchlaufen werden, bis das bestimmte Element gefunden wird. Wenn Sie das also in einer Schleife tun, entspricht dies dem folgenden Pseudocode:

for (int index = 0; index < list.size(); ++index) {
  Element e = get( (for(int i = 0; i < size; ++i) { if (i == index) return element; else element = nextElement(); }) );
}

Der Iterator ist eine abstrakte Methode zum Durchlaufen einer Liste. Daher kann er sicherstellen, dass der Durchlauf für jede Liste optimal ausgeführt wird. Tests zeigen, dass es wenig Zeitunterschied zwischen der Verwendung eines Iterators und von get (i) für eine ArrayList gibt, jedoch einen großen Zeitunterschied (zugunsten des Iterators) auf einer LinkedList.

21
TwoThe

BEARBEITEN: Wenn Sie wissen, dass size(), get(index) und set(index, value) konstante Zeitoperationen für die von Ihnen verwendeten Operationen sind (z. B. für ArrayList), würde ich persönlich die Iteratoren in diesem Fall überspringen:

for (int i = 0; i < list.size(); i++) {
    list.set(i, list.get(i) + " blah");
}

Ihr erster Ansatz ist ineffizient und möglicherweise nicht korrekt (da indexOf möglicherweise den falschen Wert zurückgibt - es wird der first -Patch zurückgegeben). Ihr zweiter Ansatz ist sehr verwirrend - die Tatsache, dass Sie zweimal next() und einmal previous aufrufen, macht es aus meiner Sicht schwer zu verstehen.

Jeder Ansatz, der List.set(index, value) verwendet, ist für eine Liste, die natürlich keinen konstanten zeitindexierten Schreibzugriff hat, ineffizient. Wie TwoThe feststellte, ist die Verwendung von ListIterator.set(value) viel besser. Der Ansatz von TwoThe, ein ListIterator zu verwenden, ist ein besserer Ansatz für allgemeine Zwecke.

Eine weitere Alternative wäre, in vielen Fällen Ihr Design zu ändern, stattdessen eine Liste in eine andere zu projizieren - entweder als Ansicht oder als Material. Wenn Sie nicht Ändern der Liste sind, müssen Sie sich nicht darum kümmern.

10
Jon Skeet

Ich habe meine Arbeit so gemacht

    String desiredInvoice="abc-123";
    long desiredAmount=1500;

    for (ListIterator<MyPurchase> it = input.getMyPurchaseList().listIterator(); it.hasNext();) {
        MyPurchase item = it.next();
        if (item.getInvoiceNo().equalsIgnoreCase(desiredInvoice)) {
            item.setPaymentAmount(desiredAmount);
            it.set(item);
            break;
        }
     }
0
Hodeifa Baswel

Intern in Iterator für for-each-Implementierung. Es gibt also keinen Unterschied zwischen diesen beiden Fällen. Wenn Sie jedoch versuchen, das Element zu ändern, wird es throwsConcurrentModificationException sein.