2008-08-20 23 views
83

Ich habe eine Liste von ganzen Zahlen, List<Integer> und ich möchte alle Integer-Objekte in Strings konvertieren, so dass mit einem neuen List<String> endet.Konvertieren Liste <Integer> zu Liste <String>

Natürlich könnte ich eine neue List<String> und Schleife durch die Liste erstellen String.valueOf() für jede ganze Zahl nennen, aber ich habe mich gefragt, ob es eine bessere war (sprich: mehr automatische) Art und Weise, es zu tun?

Antwort

64

Soweit ich weiß, Iterieren und Instanziieren ist der einzige Weg, dies zu tun. So etwas wie (für andere mögliche Hilfe, da ich sicher bin, Sie wissen, wie dies zu tun):

List<Integer> oldList = ... 
/* Specify the size of the list up front to prevent resizing. */ 
List<String> newList = new ArrayList<String>(oldList.size()) 
for (Integer myInt : oldList) { 
    newList.add(String.valueOf(myInt)); 
} 
+0

Wenn es einfach ist, nennt man das Schönheit. – Elbek

+1

Das ursprüngliche Poster schien darauf hinzuweisen, dass er darüber nachgedacht hatte, betrachtete diese Lösung jedoch als zu komplex oder langwierig. Aber ich kann mir nur schwer vorstellen, was leichter sein könnte. Ja, manchmal müssen Sie 3 oder 4 Zeilen Code schreiben, um eine Arbeit zu erledigen. – Jay

+0

Aber das bindet Sie an ArrayList. Kann dies mit der gleichen Implementierung wie die ursprüngliche Liste geschehen? –

2

@ Jonathan: Ich könnte falsch sein, aber ich glaube, dass String.valueOf() in diesem Fall nennen die String.valueOf (Object) -Funktion, anstatt Boxed zu String.valueOf (int). String.valueOf (Object) gibt nur "null" zurück, wenn es null ist, oder ruft Object.toString() auf, wenn es nicht null ist. Dies sollte kein Boxing beinhalten (obwohl offensichtlich das Instanziieren neuer String-Objekte beteiligt ist).

9

Anstatt String.valueOf zu verwenden, würde ich .toString(); es vermeidet einige der von @ johnathan.holland beschriebenen Auto-Boxen

Die Javadoc sagt, dass valueOf das gleiche wie Integer.toString() zurückgibt.

List<Integer> oldList = ... 
List<String> newList = new ArrayList<String>(oldList.size()); 

for (Integer myInt : oldList) { 
    newList.add(myInt.toString()); 
} 
+0

tun, wie von Tom Hawtin in der "gewinnenden" Antwort darauf hingewiesen, kann man keine Liste Instanz, da es nur eine Schnittstelle ist. –

+0

Heh, das wusste ich. Ich habe den Code nur geschrieben, ohne es zu versuchen. Ich werde es in meiner Antwort beheben. – ScArcher2

2

Ich denke, mit Object.toString() zu einem anderen Zweck als das Debuggen ist wahrscheinlich eine wirklich schlechte Idee, wenn auch in diesem Fall der beide funktionell gleichwertig sind (die Liste unter der Annahme hat keine Nullen). Entwickler können das Verhalten jeder toString() -Methode ohne jede Warnung ändern, einschließlich der toString() - Methoden von Klassen in der Standardbibliothek.

Sorgen Sie sich nicht einmal um die Leistungsprobleme, die durch den Boxing/Unboxing-Prozess verursacht werden. Wenn die Leistung entscheidend ist, verwenden Sie einfach ein Array. Wenn es wirklich kritisch ist, verwende kein Java. Der Versuch, die JVM auszutricksen, wird nur zu Kummer führen.

+0

+1 für "Herzschmerz" ... – Smalltown2k

9

Die Quelle für String.valueOf zeigt dies:

public static String valueOf(Object obj) { 
    return (obj == null) ? "null" : obj.toString(); 
} 

Nicht, dass es viel zählt, aber ich würde toString verwenden.

1

Sie können den "Boxen Overhead" nicht vermeiden; Java's falsche generische Container können nur Objekte speichern, also müssen Ihre Ints in Ganzzahlen eingereiht werden. Im Prinzip könnte es den Downcast von Object auf Integer vermeiden (da es sinnlos ist, weil Object gut genug für String.valueOf und Object.toString ist), aber ich weiß nicht, ob der Compiler schlau genug ist, das zu tun. Die Umwandlung von String in Objekt sollte mehr oder weniger ein No-Op sein, also wäre ich nicht geneigt, mir darüber Sorgen zu machen.

+0

der Compiler ist nicht klug genug, das zu tun. Wenn javac ausgeführt wird, werden alle generischen Informationen gelöscht. Die zugrundeliegende Implementierung einer Generikasammlung speichert IMMER Objektreferenzen. Sie können die Parametrisierung tatsächlich weglassen und einen "rohen" Typ erhalten. "Liste l = neue Liste()" versus "Liste l = neue Liste ()".das bedeutet natürlich, dass "Liste l = (Liste ) neue Liste ()" wird tatsächlich kompilieren und ausführen, aber ist natürlich sehr gefährlich. –

3

Nicht Core Java, und nicht generisch, aber die populäre Sammelsammlung Jakarta commons hat einige nützliche Abstraktionen für diese Art von Aufgabe. Insbesondere hat einen Blick auf den collect Methoden auf

CollectionUtils

Etwas zu prüfen, wenn Sie bereits commons Sammlungen in Ihrem Projekt.

+4

Verwenden Sie niemals Apache Collections. Sie sind alt, veraltet, nicht typsicher und schlecht geschrieben. – KitsuneYMG

39

Was Sie tun, ist in Ordnung, aber wenn Sie das Bedürfnis verspüren, ‚Java-it-up‘ Sie Transformer und die collect method von Apache Commons verwenden könnten, zum Beispiel:

public class IntegerToStringTransformer implements Transformer<Integer, String> { 
    public String transform(final Integer i) { 
     return (i == null ? null : i.toString()); 
    } 
} 

..und dann ..

CollectionUtils.collect(
    collectionOfIntegers, 
    new IntegerToStringTransformer(), 
    newCollectionOfStrings); 
+0

wow, cooles Zeug! – Verhogen

+1

CollectionUtils.collect (collectionOfIntegers, neu org.apache.commons.collections.functors.StringValueTransformer()); Aber StringValueTransformer verwendet die String.valueOf ... –

+5

Wenn keine neuen Arbeiten an Apache-Sammlungen durchgeführt wurden, führen sie keine Generika. – KitsuneYMG

3

Um den betroffenen Menschen zu "Boxen" in jsight Antwort: gibt es keine. String.valueOf(Object) wird hier verwendet und es wird kein Unboxing zu int durchgeführt.

Ob Sie Integer.toString() oder String.valueOf(Object) verwenden, hängt davon ab, wie Sie mit möglichen Nullen umgehen möchten. Möchten Sie eine Exception auslösen (wahrscheinlich), oder haben Sie "Null" Strings in Ihrer Liste (vielleicht). Wenn der ehemalige, möchten Sie einen NullPointerException oder einen anderen Typ zu werfen?

Auch ein kleiner Fehler in jsights Antwort: List ist eine Schnittstelle, Sie können den neuen Operator nicht darauf verwenden. Ich würde in diesem Fall wahrscheinlich einen java.util.ArrayList verwenden, zumal wir im Voraus wissen, wie lange die Liste wahrscheinlich ist.

2

Eine Antwort nur für Experten:

List<Integer> ints = ...; 
    String all = new ArrayList<Integer>(ints).toString(); 
    String[] split = all.substring(1, all.length()-1).split(", "); 
    List<String> strs = Arrays.asList(split); 
+0

Dies funktioniert aber auf Kosten der Ineffizienz. Java-Zeichenfolgen sind zwei Bytes pro Zeichen, also addiert das "," vier Byte feste Kosten pro Ganzzahl, bevor die Ganzzahl selbst gezählt wird .... unter anderem. –

+0

Ich denke, die Regex könnte eher ein Problem in Bezug auf die rohe CPU-Zyklus-Effizienz sein. In Sachen Speicher denke ich, dass eine vernünftige Implementierung (vorausgesetzt die "Sun" unangemessene Implementierung von "String") dasselbe Backing-Array (von 'all ') teilen wird, also tatsächlich sehr effizient sein wird, was wichtig wäre langfristige Leistung. Es sei denn, Sie wollen nur eines der Elemente natürlich behalten ... –

0

Just for fun, eine Lösung der jsr166y Gabel-Join-Framework, das in JDK7 sollte.

import java.util.concurrent.forkjoin.*; 

private final ForkJoinExecutor executor = new ForkJoinPool(); 
... 
List<Integer> ints = ...; 
List<String> strs = 
    ParallelArray.create(ints.size(), Integer.class, executor) 
    .withMapping(new Ops.Op<Integer,String>() { public String op(Integer i) { 
     return String.valueOf(i); 
    }}) 
    .all() 
    .asList(); 

(Haftungsausschluss:.. Nicht kompilierte Spec nicht abgeschlossen ist Etc.)

Unwahrscheinlich in JDK7 zu sein, ist ein bisschen Typinferenz und syntaktischen Zucker, dass withMapping Anruf weniger ausführlich zu machen:

.withMapping(#(Integer i) String.valueOf(i)) 
0

Dies ist so eine grundlegende Sache zu tun, würde ich nicht eine externe Bibliothek verwenden (es wird eine Abhängigkeit in Ihrem Projekt, die Sie wahrscheinlich nicht brauchen).

Wir haben eine Klasse von statischen Methoden speziell für diese Art von Aufgaben. Weil der Code dafür so einfach ist, lassen wir Hotspot die Optimierung für uns tun. Dies scheint in letzter Zeit ein Thema in meinem Code zu sein: schreibe sehr einfachen (direkten) Code und lass Hotspot seine Magie wirken. Wir haben selten Leistungsprobleme mit Code wie diesem - wenn eine neue VM-Version kommt, bekommst du alle zusätzlichen Geschwindigkeitsvorteile etc.

So sehr ich Jakarta-Sammlungen liebe, unterstützen sie Generics nicht und verwenden 1.4 als LCD . Ich bin vorsichtig bei Google Collections, da sie als Alpha-Support-Level aufgeführt sind!

82

Mit Google Collections from Guava-Project, könnten Sie die transform Methode in der Lists Klasse verwenden

import com.google.common.collect.Lists; 
import com.google.common.base.Functions 

List<Integer> integers = Arrays.asList(1, 2, 3, 4); 

List<String> strings = Lists.transform(integers, Functions.toStringFunction()); 

Die List zurück von transform ist eine Ansicht auf der Trägerliste - die Transformation wird bei jedem Zugriff auf die transformierte angewendet werden Liste.

Beachten Sie, dass Functions.toStringFunction() einen NullPointerException wirft, wenn Sie auf null angewendet werden. Verwenden Sie ihn daher nur, wenn Sie sicher sind, dass Ihre Liste nicht null enthält.

+1

Es wird nett sein, wenn es neben Functions.toStringFunction() – ThiamTeck

+1

mehr fertige Funktionen gibt, aber vielleicht nicht so schnell .. 1 zusätzlicher Funktionsaufruf pro Wert? – h3xStream

+3

HotSpot kann Inline-Funktionsaufrufe ausführen - wenn es also genug heißt, sollte es keinen Unterschied machen. –

2

Lambdaj ermöglicht dies auf eine sehr einfache und lesbare Weise zu tun.Angenommen, Sie haben eine Liste von Integer und möchten diese in der entsprechenden String-Darstellung konvertieren, könnten Sie etwas Ähnliches schreiben;

Lambdaj wendet die Konvertierungsfunktion nur während der Iteration des Ergebnisses an.

8

Hier ist eine One-Liner-Lösung ohne Betrug mit einer Nicht-JDK-Bibliothek.

List<String> strings = Arrays.asList(list.toString().replaceAll("\\[(.*)\\]", "$1").split(", ")); 
+0

+1 für reine Hakerei. – metasim

-1

Ich wollte nur mit einer objektorientierten Lösung für das Problem einspielen.

Wenn Sie Domänenobjekte modellieren, befindet sich die Lösung in den Domänenobjekten. Die Domain hier ist eine Liste von ganzen Zahlen, für die wir String-Werte haben wollen.

Der einfachste Weg wäre, die Liste überhaupt nicht zu konvertieren.

Dass gesagt wird, um ohne Konvertierung zu konvertieren, die ursprüngliche Liste von Integer Wertänderung zur Liste, wo Wert ungefähr so ​​aussieht ...

class Value { 
    Integer value; 
    public Integer getInt() 
    { 
     return value; 
    } 
    public String getString() 
    { 
     return String.valueOf(value); 
    } 
} 

Dies wird schneller sein und nimmt weniger Speicher als das Kopieren der Liste.

Viel Glück!

52

Lösung für Java 8. Ein bisschen länger als die Guava, aber zumindest müssen Sie keine Bibliothek installieren.

import java.util.Arrays; 
import java.util.List; 
import java.util.stream.Collectors; 

//... 

List<Integer> integers = Arrays.asList(1, 2, 3, 4); 
List<String> strings = integers.stream().map(Object::toString) 
             .collect(Collectors.toList()); 
+0

Während dies für das 'toString'-Beispiel etwas länger ist, ist es für Konvertierungen, die nicht von der Guava-Funktionsbibliothek unterstützt werden, kürzer. Benutzerdefinierte Funktionen sind immer noch einfach, aber es ist wesentlich mehr Code als dieser Java 8-Stream – lightswitch05

5

Eine andere Lösung mit Guava und Java 8

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); 
List<String> strings = Lists.transform(numbers, number -> String.valueOf(number)); 
0

ich keine Lösung sah, die die Haupt Komplexität des Raumes folgt. Wenn die Liste der Integer eine große Anzahl von Elementen hat, dann ist es ein großes Problem .

It will be really good to remove the integer from the List<Integer> and free 
the space, once it's added to List<String>. 

Wir können Iterator verwenden das gleiche zu erreichen.

List<Integer> oldList = new ArrayList<>(); 
    oldList.add(12); 
    oldList.add(14); 
    ....... 
    ....... 

    List<String> newList = new ArrayList<String>(oldList.size()); 
    Iterator<Integer> itr = oldList.iterator(); 
    while(itr.hasNext()){ 
     newList.add(itr.next().toString()); 
     itr.remove(); 
    } 
Verwandte Themen