Konvertieren von List <Integer> in List <String>

105

Ich habe eine Liste von Ganzzahlen List<Integer>und möchte alle Ganzzahlobjekte in Zeichenfolgen konvertieren, um eine neue zu erhalten List<String>.

Natürlich könnte ich eine neue List<String>Liste erstellen und die Liste String.valueOf()für jede Ganzzahl durchlaufen , aber ich habe mich gefragt, ob es eine bessere (sprich: automatischere ) Möglichkeit gibt, dies zu tun.

ChrisThomas123
quelle

Antworten:

77

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

List<Integer> oldList = ...
/* Specify the size of the list up front to prevent resizing. */
List<String> newList = new ArrayList<>(oldList.size());
for (Integer myInt : oldList) { 
  newList.add(String.valueOf(myInt)); 
}
jsight
quelle
Wenn es einfach ist, nennt man das Schönheit.
Elbek
1
Das Originalplakat schien darauf hinzudeuten, dass er darüber nachgedacht hatte, diese Lösung jedoch für zu komplex oder zu langwierig hielt. Aber ich kann mir kaum vorstellen, was einfacher sein könnte. Ja, manchmal müssen Sie 3 oder 4 Codezeilen schreiben, um einen Job zu erledigen.
Jay
Aber das bindet dich an ArrayList. Kann dies mit derselben Implementierung wie in der ursprünglichen Liste durchgeführt werden?
Alianos
@ Andreas oldList.getClass (). NewInstance () wird tun
Lluis Martinez
96

Mit Google Collections von Guava-Project können Sie die transformMethode 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());

Das Listzurückgegebene von transformist eine Ansicht der Hintergrundliste - die Transformation wird bei jedem Zugriff auf die transformierte Liste angewendet.

Beachten Sie, dass bei Anwendung auf null Functions.toStringFunction()ein a NullPointerExceptionausgelöst wird. Verwenden Sie es daher nur, wenn Sie sicher sind, dass Ihre Liste keine null enthält.

Ben Lings
quelle
1
Es wird schön sein, wenn es neben Functions.toStringFunction ()
ThiamTeck
1
sauber aber vielleicht nicht so schnell .. 1 zusätzlicher Funktionsaufruf pro Wert?
h3xStream
3
HotSpot kann Funktionsaufrufe inline ausführen. Wenn es also genug aufgerufen wird, sollte es keinen Unterschied machen.
Ben Lings
3
Ich stimme dem nicht zu, weil es in der Tat eine Lösung ist. Aber Leute zu ermutigen, eine Bibliotheksabhängigkeit hinzuzufügen, um solch eine einfache Aufgabe zu lösen, ist für mich ein No-Go.
Estani
1
Gute Lösung, wenn Sie Guava bereits in unserer Lösung verwenden.
Dudinha-Dedalus
86

Lösung für Java 8. Etwas länger als die für 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());
Trejkaz
quelle
1
Während dies für das toStringBeispiel etwas länger ist , wird es für Konvertierungen, die von der Guava-Funktionsbibliothek nicht unterstützt werden, kürzer. Benutzerdefinierte Funktionen sind immer noch einfach, aber es ist deutlich mehr Code als dieser Java 8-Stream
Lightswitch05
40

Was Sie tun, ist in Ordnung, aber wenn Sie das Bedürfnis haben, Java-it-up zu verwenden, können Sie einen Transformer und die Collect-Methode von Apache Commons verwenden , z.

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);
SCdF
quelle
1
CollectionUtils.collect (collectionOfIntegers, neue org.apache.commons.collections.functors.StringValueTransformer ()); Aber StringValueTransformer verwendet den String.valueOf ...
Kannan Ekanath
5
Sofern keine neuen Arbeiten an Apache-Sammlungen durchgeführt wurden, werden keine Generika erstellt.
KitsuneYMG
1
Das ist wirklich Java-ing-it down. Dies ist kein idiomatisches Java, sondern eher eine funktionale Programmierung. Wenn wir in Java 8 Schließungen erhalten, können Sie es vielleicht als idiomatisches Java bezeichnen.
Christoffer Hammarström
Sie möchten auf jeden Fall Collections4 dafür verwenden (nicht die alten 3.x-Sammlungen), um Generika zu unterstützen: commons.apache.org/proper/commons-collections/apidocs/org/…
JRA_TLL
Definieren einer neuen Klasse, nur um "OOP oder idiomatischer" zu sein ... Ich sehe nicht, wie dies besser ist als die einfache Schleife für jede Schleife. Es erfordert mehr Code und verschiebt die Funktionalität (die durch anonyme Klassen gemindert werden könnte, aber immer noch). Dieser funktionale Stil wird erst dann nützlich, wenn es eine anständige Syntax gibt (dh Lambda-Ausdrücke seit Java 8), wie sie funktionale Sprachen seit Jahrzehnten bereitstellen.
TheOperator
9

Die Quelle für String.valueOf zeigt Folgendes:

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

Nicht, dass es viel ausmacht, aber ich würde toString verwenden.

Mike Polen
quelle
9

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

Das Javadoc sagt, dass valueOf dasselbe zurückgibt wie Integer.toString ().

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

for (Integer myInt : oldList) { 
  newList.add(myInt.toString()); 
}
ScArcher2
quelle
Wie Tom Hawtin in der "Gewinner" -Antwort hervorhob, kann man List <String> nicht instanziieren, da es sich nur um eine Schnittstelle handelt.
Stu Thompson
Heh das wusste ich. Ich habe nur den Code geschrieben, ohne ihn auszuprobieren. Ich werde es in meiner Antwort beheben.
ScArcher2
9

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

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

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));
Sandrozbinden
quelle
3

Nicht Java-Kern und nicht generisch, aber die beliebte Sammlungsbibliothek von Jakarta Commons bietet einige nützliche Abstraktionen für diese Art von Aufgabe. Schauen Sie sich insbesondere die Erfassungsmethoden an

CollectionUtils

Beachten Sie Folgendes, wenn Sie in Ihrem Projekt bereits Commons-Sammlungen verwenden.

serg10
quelle
4
Verwenden Sie niemals Apache-Sammlungen. Sie sind alt, veraltet, nicht typsicher und schlecht geschrieben.
KitsuneYMG
3

An die Leute, die in jsights Antwort über "Boxen" besorgt sind: Es gibt keine. String.valueOf(Object)wird hier verwendet und es wird nie ein Unboxing intdurchgeführt.

Ob Sie verwenden Integer.toString()oder String.valueOf(Object)davon abhängen, wie Sie mit möglichen Nullen umgehen möchten. Möchten Sie (wahrscheinlich) eine Ausnahme auslösen oder "null" Zeichenfolgen in Ihrer Liste haben (möglicherweise). Wenn erstere, möchten Sie einen NullPointerExceptionoder einen anderen Typ werfen ?

Ein kleiner Fehler in der Antwort von jsight Listist eine Schnittstelle, für die Sie den neuen Operator nicht verwenden können. Ich würde java.util.ArrayListin diesem Fall wahrscheinlich ein verwenden , zumal wir im Voraus wissen, wie lang die Liste wahrscheinlich ist.

erickson
quelle
3
List<String> stringList = integerList.stream().map((Object s)->String.valueOf(s)).collect(Collectors.toList())
Mahesh Yadav
quelle
2

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

jsight
quelle
2

Ich denke, die Verwendung von Object.toString () für einen anderen Zweck als das Debuggen ist wahrscheinlich eine wirklich schlechte Idee, obwohl in diesem Fall die beiden funktional gleichwertig sind (vorausgesetzt, die Liste enthält keine Nullen). Es steht Entwicklern frei, das Verhalten einer toString () -Methode ohne Vorwarnung zu ändern, einschließlich der toString () -Methoden aller Klassen in der Standardbibliothek.

Machen Sie sich nicht einmal Sorgen über die Leistungsprobleme, die durch den Box- / Unboxing-Prozess verursacht werden. Wenn die Leistung kritisch ist, verwenden Sie einfach ein Array. Wenn es wirklich kritisch ist, verwenden Sie kein Java. Der Versuch, die JVM auszutricksen, führt nur zu Herzschmerz.

Outlaw Programmer
quelle
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);
Tom Hawtin - Tackline
quelle
Dies funktioniert jedoch auf Kosten der Ineffizienz. Java-Strings sind zwei Bytes pro Zeichen, daher addiert das "," vier Byte Fixkosten pro Ganzzahl, bevor die Ganzzahl selbst gezählt wird ... unter anderem.
Robert Christian
Ich denke, der reguläre Ausdruck könnte eher ein Problem in Bezug auf die Effizienz des rohen CPU-Zyklus sein. In Bezug auf den Speicher denke ich, dass eine vernünftige Implementierung (unter der Annahme, dass die "Sun" -Unvernünftige Implementierung von String) dasselbe Backing-Array (von all) verwendet, also tatsächlich sehr speichereffizient ist, was für die langfristige Leistung wichtig wäre. Es sei denn, Sie möchten natürlich nur eines der Elemente behalten ...
Tom Hawtin - Tackline
2

Lambdaj ermöglicht dies auf sehr einfache und lesbare Weise. Angenommen, Sie haben eine Liste mit Ganzzahlen und möchten diese in die entsprechende Zeichenfolgendarstellung konvertieren. Dann könnten Sie so etwas schreiben.

List<Integer> ints = asList(1, 2, 3, 4);
Iterator<String> stringIterator = convertIterator(ints, new Converter<Integer, String> {
    public String convert(Integer i) { return Integer.toString(i); }
}

Lambdaj wendet die Konvertierungsfunktion nur an, während Sie das Ergebnis iterieren.

Mario Fusco
quelle
1

Sie können den "Boxaufwand" nicht vermeiden; Javas generische Faux-Container können nur Objekte speichern, daher müssen Ihre Ints in Ganzzahlen eingeschlossen sein. Im Prinzip könnte es den Downcast von Object zu Integer vermeiden (da es sinnlos ist, weil Object sowohl für String.valueOf als auch für Object.toString gut genug ist), aber ich weiß nicht, ob der Compiler dafür klug genug ist. Die Konvertierung von String zu Object sollte mehr oder weniger ein No-Op sein, daher würde ich mich nicht darum kümmern.

DrPizza
quelle
Der Compiler ist dafür NICHT schlau genug. Wenn javac ausgeführt wird, werden tatsächlich alle generischen Typinformationen entfernt. Die zugrunde liegende Implementierung einer generischen Sammlung speichert IMMER Objektreferenzen. Sie können die <T> -Parametrisierung tatsächlich weglassen und einen "rohen" Typ erhalten. "Liste l = neue Liste ()" versus "Liste <String> l = neue Liste <String> ()". Dies bedeutet natürlich, dass "List <String> l = (List <String>) new List <Integer> ()" tatsächlich kompiliert und ausgeführt wird, aber offensichtlich sehr gefährlich ist.
Dave Dopson
1

Ich habe keine Lösung gesehen, die dem Prinzip der Raumkomplexität folgt. Wenn die Liste der Ganzzahlen eine große Anzahl von Elementen enthält, ist dies 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 den Iterator verwenden, um dasselbe 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();
    }
nagendra547
quelle
1

Verwenden von Streams: Wenn das Ergebnis eine Liste von Ganzzahlen ( List<Integer> result) ist, dann:

List<String> ids = (List<String>) result.stream().map(intNumber -> Integer.toString(intNumber)).collect(Collectors.toList());

Eine der Möglichkeiten, es zu lösen. Hoffe das hilft.

Shirish Singh
quelle
1

Eine etwas präzisere Lösung mit der forEach-Methode in der ursprünglichen Liste:

    List<Integer> oldList = Arrays.asList(1, 2, 3, 4, 5);
    List<String> newList = new ArrayList<>(oldList.size());
    oldList.forEach(e -> newList.add(String.valueOf(e)));
Solubris
quelle
0

Nur zum Spaß eine Lösung mit dem Fors-Join-Framework jsr166y, das in JDK7 verwendet werden 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 kompiliert. Spezifikation ist nicht finalisiert. Usw.)

In JDK7 ist es unwahrscheinlich, dass ein bisschen Typinferenz und syntaktischer Zucker vorhanden sind, um den withMapping-Aufruf weniger ausführlich zu machen:

    .withMapping(#(Integer i) String.valueOf(i))
Tom Hawtin - Tackline
quelle
0

Dies ist eine so grundlegende Aufgabe, dass ich keine externe Bibliothek verwenden würde (dies führt zu einer Abhängigkeit in Ihrem Projekt, die Sie wahrscheinlich nicht benötigen).

Wir haben eine Klasse statischer Methoden, die speziell für diese Art von Aufgaben entwickelt wurden. Da der Code dafür so einfach ist, lassen wir Hotspot die Optimierung für uns durchführen. Dies scheint in letzter Zeit ein Thema in meinem Code zu sein: Schreiben Sie sehr einfachen (unkomplizierten) Code und lassen Sie Hotspot seine Magie wirken. Wir haben selten Leistungsprobleme mit Code wie diesem - wenn eine neue VM-Version auf den Markt kommt, erhalten Sie alle zusätzlichen Geschwindigkeitsvorteile usw.

So sehr ich Jakarta-Kollektionen liebe, sie unterstützen keine Generika und verwenden 1.4 als LCD. Ich bin vorsichtig mit Google-Sammlungen, da diese als Alpha-Support-Level aufgeführt sind!


quelle
-1

Ich wollte mich nur auf eine objektorientierte Lösung des Problems einlassen.

Wenn Sie Domänenobjekte modellieren, liegt die Lösung in den Domänenobjekten. Die Domäne hier ist eine Liste von Ganzzahlen, für die Zeichenfolgenwerte erforderlich sind.

Am einfachsten wäre es, die Liste überhaupt nicht zu konvertieren.

Um jedoch ohne Konvertierung zu konvertieren, ändern Sie die ursprüngliche Liste von Integer in List of Value, wobei Value ungefähr so ​​aussieht ...

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

Dies ist schneller und beansprucht weniger Speicher als das Kopieren der Liste.

Viel Glück!

Rodney P. Barbati
quelle