List <Integer> Listeye <String> dönüştürülüyor


105

Bir tamsayı listem var List<Integer>ve tüm tamsayı nesnelerini Dizelere dönüştürmek istiyorum, böylece yeni bir List<String>.

Doğal olarak, her bir tamsayıyı List<String>çağıran listede yeni bir döngü oluşturabilirim String.valueOf(), ancak bunu yapmanın daha iyi (okuma: daha otomatik ) bir yolu olup olmadığını merak ediyordum.

Yanıtlar:


77

Bildiğim kadarıyla, bunu yapmanın tek yolu yinelemek ve örneklemek. Şöyle bir şey (diğerleri için potansiyel yardım için, çünkü bunu nasıl yapacağınızı bildiğinizden eminim):

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)); 
}

Basit olduğunda buna güzellik denir.
Elbek

1
Orijinal afiş, bunu düşündüğünü ancak bu çözümü çok karmaşık veya sıkıcı bulduğunu gösteriyor gibiydi. Ama neyin daha kolay olabileceğini hayal etmekte zorlanıyorum. Evet, bazen bir işi bitirmek için 3 veya 4 satır kod yazmanız gerekir.
Jay

Ancak bu sizi ArrayList'e bağlar. Bu, orijinal listeyle aynı uygulama kullanılarak yapılabilir mi?
alianos

@Andreas oldList.getClass (). NewInstance () yapacak
Lluis Martinez

96

Guava-Project'teki Google Koleksiyonları kullanarak transform, Listeler sınıfındaki yöntemi kullanabilirsiniz

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());

ListTarafından döndürülen transformbir olduğunu görünüşüdür dönüşüm dönüştürülmüş listesine her bir erişim uygulanacak - taşıyıcı listesinde.

Boş değerine uygulandığında Functions.toStringFunction()bunun bir atacağına dikkat edin NullPointerException, bu nedenle yalnızca listenizin null içermeyeceğinden eminseniz kullanın.


1
Functions.toStringFunction ()
ThiamTeck

1
temiz ama belki o kadar hızlı değil .. Değer başına 1 ekstra işlev çağrısı?
h3xStream

3
HotSpot, işlev çağrılarını satır içi yapabilir - bu nedenle, yeterince çağrılırsa, bir fark yaratmamalıdır.
Ben Lings

3
Bunu olumsuz oylamıyorum çünkü bu gerçekten bir çözüm. Ancak insanları böylesine basit bir görevi çözmek için bir kütüphane bağımlılığı eklemeye teşvik etmek benim için uygun değil.
estani

1
Çözümümüzde zaten Guava kullanıyorsanız güzel bir çözüm.
dudinha-dedalus

86

Java 8 için Çözüm. Guava'dan biraz daha uzun, ancak en azından bir kitaplık kurmanıza gerek yok.

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());

1
Bu, toStringörnek için biraz daha uzun olsa da , Guava'nın İşlevler kitaplığı tarafından desteklenmeyen dönüştürmeler için daha kısa olur. Özel İşlevler hala kolay, ancak bu Java 8 akışından çok daha fazla kod
içeriyor

40

Ne yapıyoruz iyi, ama sen ihtiyacı hissediyorum eğer 'Java-it-up' Bir kullanabilirsiniz Trafo ve toplamak yöntemi gelen Apache Commons , örneğin:

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

..ve sonra..

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

1
CollectionUtils.collect (collectionOfIntegers, new org.apache.commons.collections.functors.StringValueTransformer ()); Ancak, StringValueTransformer, String.valueOf ...
Kannan

5
Apache koleksiyonları üzerinde yeni bir çalışma yapılmadıkça jenerik yapmazlar.
KitsuneYMG

1
Bu gerçekten Java yazıyor. Bu deyimsel Java değildir ve daha çok işlevsel programlama gibidir. Belki Java 8'de kapanışımız olduğunda, buna deyimsel Java diyebilirsin.
Christoffer Hammarström

Kesinlikle bunun için Koleksiyonlar4'ü (eski 3.x Koleksiyonları değil) jenerik desteği için kullanmak istiyorsunuz: commons.apache.org/proper/commons-collections/apidocs/org/…
JRA_TLL

Yeni bir sınıfı sadece "daha fazla OOP veya deyimsel" olacak şekilde tanımlamak ... Bunun her döngü için basit olandan nasıl daha iyi olduğunu anlamıyorum. Daha fazla kod gerektirir ve işlevselliği uzaklaştırır (anonim sınıflar tarafından azaltılabilir, ancak yine de). Bu işlevsel stil, ancak işlevsel dillerin onlarca yıldır sağladığı gibi, düzgün bir sözdizimi (yani, Java 8'den beri lambda ifadeleri) olduğunda yararlı olmaya başlar.
TheOperator

9

String.valueOf kaynağı şunu gösterir:

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

Çok önemli değil, ama toString'i kullanırdım.


9

String.valueOf kullanmak yerine .toString (); @ johnathan.holland tarafından açıklanan bazı otomatik bokstan kaçınır

Javadoc, valueOf'un Integer.toString () ile aynı şeyi döndürdüğünü söyler.

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

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

Tom Hawtin'in 'kazanan' yanıtta belirttiği gibi, List <String> sadece bir arayüz olduğu için örneklenemez.
Stu Thompson

Heh bunu biliyordum. Kodu denemeden yazdım. Cevabımda düzelteceğim.
ScArcher2

9

İşte JDK olmayan bir kitaplıkla hile yapmadan tek satırlık bir çözüm.

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

7

Guava ve Java 8 kullanan başka bir çözüm

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

3

Çekirdek Java değil ve jenerik olmayan, ancak popüler Jakarta commons koleksiyonları kitaplığında bu tür görevler için bazı yararlı soyutlamalar var. Özellikle, aşağıdaki toplama yöntemlerine bir göz atın

Koleksiyon

Projenizde halihazırda ortak koleksiyonları kullanıyorsanız dikkate almanız gereken bir şey.


4
Apache Koleksiyonlarını asla kullanmayın. Eski, modası geçmiş, güvenli değil ve kötü yazılmış.
KitsuneYMG

3

Jsight'ın cevabında "boks" konusunda endişelenen kişilere: hiçbiri yok. String.valueOf(Object)burada kullanılır ve hiçbir zaman kutudan çıkarma intyapılmaz.

Kullanmanız Integer.toString()veya kullanıp kullanmamanız String.valueOf(Object), olası boş değerleri nasıl işlemek istediğinize bağlıdır. Bir istisna mı atmak istiyorsunuz (muhtemelen) yoksa listenizde "boş" Dizeler mi var (belki). İlki ise, bir NullPointerExceptionveya başka bir tür atmak ister misiniz ?

Ayrıca, jsight'ın yanıtındaki küçük bir kusur: Listbir arayüz, üzerinde yeni operatörü kullanamazsınız. java.util.ArrayListBu durumda muhtemelen a kullanırım , özellikle de listenin ne kadar uzun olacağını önceden bildiğimiz için.


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

2

@Jonathan: Yanılmış olabilirim, ancak bu durumda String.valueOf () 'un String.valueOf (int)' e kutulanmak yerine String.valueOf (Object) fonksiyonunu çağıracağına inanıyorum. String.valueOf (Object), boşsa "null" döndürür veya boş değilse Object.toString () öğesini çağırır; bu, kutuyu içermemelidir (açık bir şekilde yeni dize nesnelerinin başlatılması söz konusudur).


2

Hata ayıklama dışında herhangi bir amaçla Object.toString () kullanmanın muhtemelen gerçekten kötü bir fikir olduğunu düşünüyorum, bu durumda ikisi işlevsel olarak eşdeğer olsa da (listenin boş değeri olmadığı varsayılırsa). Geliştiriciler, standart kitaplıktaki herhangi bir sınıfın toString () yöntemleri dahil olmak üzere herhangi bir toString () yönteminin davranışını herhangi bir uyarı olmaksızın değiştirmekte özgürdür.

Kutulama / kutudan çıkarma işleminin neden olduğu performans sorunları hakkında endişelenmeyin bile. Performans kritikse, sadece bir dizi kullanın. Gerçekten kritikse, Java kullanmayın. JVM'yi zekice alt etmeye çalışmak sadece gönül yarasına yol açacaktır.


2

Yalnızca uzmanlar için bir cevap:

    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);

Bu işe yarar ama verimsizlik pahasına. Java Dizeleri karakter başına iki bayttır, bu nedenle "," tamsayının kendisini saymadan önce tamsayı başına dört bayt sabit maliyet ekler.
Robert Christian

Normal ifadenin, ham CPU döngüsü verimliliği açısından daha fazla sorun olabileceğini düşünüyorum. Bellek açısından, makul bir uygulamanın ("Sun" ın mantıksız uygulamasını varsayarsak String) aynı destek dizisini (from all) paylaşacağını tahmin ediyorum , bu nedenle aslında uzun vadeli performans için önemli olan bellek açısından oldukça verimli olacaktır. Tabi ki unsurlardan sadece birini korumak istemediğiniz sürece ...
Tom Hawtin -

2

Lambdaj , bunu çok basit ve okunabilir bir şekilde yapmaya izin verir. Örneğin, bir Tamsayı listeniz olduğunu ve bunları karşılık gelen Dize gösterimine dönüştürmek istediğinizi varsayarsak, böyle bir şey yazabilirsiniz;

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, dönüştürme işlevini yalnızca siz sonucu yinelerken uygular.


1

"Boks ek yükünden" kaçınamazsınız; Java'nın sahte jenerik kapsayıcıları yalnızca Nesneleri depolayabilir, bu nedenle girişlerinizin Tamsayılar halinde kutulanması gerekir. Prensipte, Object'ten Tamsayıya indirgemeyi önleyebilir (anlamsız olduğu için, çünkü Object hem String.valueOf hem de Object.toString için yeterince iyi) ancak derleyicinin bunu yapacak kadar akıllı olup olmadığını bilmiyorum. String'den Object'e dönüşüm az ya da çok işlemsiz olmalı, bu yüzden bu konuda endişelenme eğilimim olmayacak.


derleyici bunu yapacak kadar akıllı DEĞİLDİR. Javac çalıştığında, aslında tüm jenerik tür bilgilerini çıkarır. Genel bir koleksiyonun temelindeki uygulama HER ZAMAN Nesne referanslarını depolar. Aslında <T> parametrizasyonunu atlayabilir ve "ham" bir tür elde edebilirsiniz. "List l = new List ()" ve "List <String> l = new List <String> ()". Tabii ki bu, "List <String> l = (List <String>) new List <Integer> ()" gerçekten derlenecek ve çalıştırılacak anlamına gelir, ancak açıkçası çok tehlikelidir.
Dave Dopson

1

Uzay karmaşıklığı ilkesini takip eden herhangi bir çözüm görmedim. Tam sayılar listesinde çok sayıda eleman varsa bu büyük bir problemdir.

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

Aynı şeyi başarmak için yineleyici kullanabiliriz.

    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();
    }

1

Akışları Kullanma: Eğer sonucun tamsayılar listesi ( List<Integer> result) olduğunu varsayalım:

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

Bunu çözmenin yollarından biri. Bu yardımcı olur umarım.


1

Orijinal listedeki forEach yöntemini kullanan biraz daha kısa bir çözüm:

    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)));

0

Sadece eğlence için, JDK7'de olması gereken jsr166y çatal-birleştirme çerçevesini kullanan bir çözüm.

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();

(Sorumluluk reddi: Derlenmedi. Spesifikasyon kesinleştirilmedi. Vb.)

JDK7'de olma olasılığı düşük olan, withMapping çağrısını daha az ayrıntılı hale getirmek için biraz tür çıkarımı ve sözdizimsel şekerdir:

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

0

Bu o kadar basit bir şey ki, harici bir kitaplık kullanmam (projenizde muhtemelen ihtiyacınız olmayan bir bağımlılığa neden olur).

Bu tür işleri yapmak için özel olarak hazırlanmış bir statik yöntem sınıfımız var. Bunun kodu çok basit olduğu için Hotspot'un bizim için optimizasyonu yapmasına izin veriyoruz. Bu son zamanlarda kodumda bir tema gibi görünüyor: çok basit (anlaşılır) bir kod yazın ve Hotspot'un sihrini yapmasına izin verin. Bunun gibi kodlarla ilgili nadiren performans sorunları yaşıyoruz - yeni bir VM sürümü çıktığında tüm ekstra hız avantajlarından yararlanabilirsiniz.

Jakarta koleksiyonlarını sevdiğim kadar, Generics'i desteklemiyorlar ve LCD olarak 1.4 kullanıyorlar. Alfa destek seviyesi olarak listelendikleri için Google Koleksiyonları konusunda ihtiyatlıyım!


-1

Sadece soruna nesneye yönelik bir çözüm bulmak istedim.

Etki alanı nesnelerini modelliyorsanız, çözüm etki alanı nesnelerindedir. Buradaki alan, dize değerlerini istediğimiz tam sayıların listesidir.

En kolay yol, listeyi hiç dönüştürmemek olacaktır.

Bununla birlikte, dönüştürmeden dönüştürmek için, orijinal Tamsayı listesini Değerin şöyle göründüğü Değer Listesi olarak değiştirin ...

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

Bu daha hızlı olacak ve Listeyi kopyalamaktan daha az hafıza kaplayacaktır.

İyi şanslar!

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.