การแปลงรายการ <Integer> เป็น List <String>


105

ฉันมีรายการจำนวนเต็มList<Integer>และฉันต้องการแปลงอ็อบเจ็กต์จำนวนเต็มทั้งหมดเป็น Strings ดังนั้นจึงจบด้วยList<String>.

โดยปกติฉันสามารถสร้างรายการใหม่List<String>และวนซ้ำรายการที่เรียกString.valueOf()หาจำนวนเต็มแต่ละรายการได้แต่ฉันสงสัยว่ามีวิธีที่ดีกว่า (อ่าน: อัตโนมัติมากขึ้น ) หรือไม่?

คำตอบ:


77

เท่าที่ฉันรู้การทำซ้ำและสร้างอินสแตนซ์เป็นวิธีเดียวที่จะทำได้ บางอย่างเช่น (สำหรับความช่วยเหลืออื่น ๆ ที่เป็นไปได้เนื่องจากฉันแน่ใจว่าคุณรู้วิธีดำเนินการนี้):

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

เมื่อเป็นเรื่องง่ายนี้เรียกว่าความงาม
Elbek

1
โปสเตอร์ต้นฉบับดูเหมือนจะบ่งบอกว่าเขาคิดเรื่องนี้ แต่คิดว่าวิธีนี้ซับซ้อนหรือน่าเบื่อเกินไป แต่ฉันยากที่จะจินตนาการว่าอะไรจะง่ายกว่านี้ ใช่บางครั้งคุณต้องเขียนโค้ด 3 หรือ 4 บรรทัดเพื่อให้งานสำเร็จลุล่วง
Jay

แต่นั่นจะผูกคุณกับ ArrayList สามารถทำได้โดยใช้การใช้งานเดียวกันกับรายการเดิมหรือไม่
alianos-

@Andreas oldList.getClass (). newInstance () จะทำ
Lluis Martinez

96

การใช้Google Collections จาก Guava-Projectคุณสามารถใช้transformวิธีนี้ในคลาสLists

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

สิ่งที่Listส่งคืนโดยtransformเป็นมุมมองในรายการสำรอง - การเปลี่ยนแปลงจะถูกนำไปใช้กับการเข้าถึงแต่ละรายการที่ถูกแปลง

โปรดทราบว่าFunctions.toStringFunction()จะโยน a NullPointerExceptionเมื่อนำไปใช้กับ null ดังนั้นควรใช้เฉพาะเมื่อคุณแน่ใจว่ารายการของคุณจะไม่มีค่าว่าง


1
จะดีมากถ้ามีฟังก์ชั่นที่พร้อมใช้งานมากขึ้นข้าง Functions.toStringFunction ()
ThiamTeck

1
สะอาด แต่อาจจะไม่เร็วเท่า .. 1 ฟังก์ชั่นพิเศษเรียกต่อค่า?
h3xStream

3
HotSpot สามารถเรียกใช้ฟังก์ชันแบบอินไลน์ได้ดังนั้นหากเรียกว่าเพียงพอก็ไม่ควรสร้างความแตกต่าง
Ben Lings

3
ฉันไม่ลงคะแนนเรื่องนี้เพราะมันเป็นวิธีแก้ปัญหา แต่การส่งเสริมให้ผู้คนเพิ่มการพึ่งพาห้องสมุดเพื่อแก้ปัญหาง่ายๆเช่นนี้เป็นเรื่องที่ไม่ต้องทำสำหรับฉัน
เอสทานี

1
ทางออกที่ดีหากคุณใช้ Guava อยู่แล้วในโซลูชันของเรา
dudinha-dedalus

86

โซลูชันสำหรับ Java 8 ยาวกว่า Guava one เล็กน้อย แต่อย่างน้อยคุณไม่ต้องติดตั้งไลบรารี

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
แม้ว่าตัวอย่างนี้จะยาวกว่าเล็กน้อยtoStringแต่ก็สั้นลงสำหรับการแปลงที่ไม่รองรับโดยไลบรารี Functions ของ Guava ฟังก์ชั่นที่กำหนดเองยังคงง่าย แต่ก็มีโค้ดมากกว่าอย่างมีนัยสำคัญจากนั้นสตรีม Java 8 นี้
lightswitch05

40

สิ่งที่คุณทำนั้นดี แต่ถ้าคุณรู้สึกว่าจำเป็นต้อง 'Java-it-up' คุณสามารถใช้TransformerและวิธีการรวบรวมจากApache Commonsเช่น:

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

.. แล้วก็ ..

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

1
CollectionUtils.collect (collectionOfIntegers ใหม่ org.apache.commons.collections.functors.StringValueTransformer ()); แต่ StringValueTransformer ใช้ String.valueOf ...
กรรณเอกนาถ

5
เว้นแต่จะมีการทำงานใหม่ในคอลเลกชัน apache พวกเขาจะไม่ทำแบบทั่วไป
KitsuneYMG

1
นี่มันลง Java จริงๆ นี่ไม่ใช่ Java ที่เป็นสำนวนและเหมือนกับการเขียนโปรแกรมเชิงฟังก์ชัน บางทีเมื่อเราถูกปิดใน Java 8 คุณสามารถเรียกมันว่า Java สำนวน
Christoffer Hammarström

แน่นอนคุณต้องการใช้ Collections4 สำหรับสิ่งนั้น (ไม่ใช่คอลเลกชัน 3.x เก่า) เพื่อรองรับ generics: commons.apache.org/proper/commons-collections/apidocs/org/…
JRA_TLL

การกำหนดคลาสใหม่ให้เป็น "OOP เพิ่มเติมหรือสำนวน" ... ฉันไม่เห็นว่าสิ่งนี้จะดีไปกว่าความเรียบง่ายสำหรับแต่ละลูปอย่างไร ต้องใช้รหัสมากขึ้นและย้ายฟังก์ชันออกไป (ซึ่งอาจลดลงโดยคลาสที่ไม่ระบุชื่อ แต่ก็ยังคงอยู่) รูปแบบการทำงานนี้จะเริ่มมีประโยชน์ก็ต่อเมื่อมีไวยากรณ์ที่เหมาะสม (เช่นนิพจน์แลมบ์ดาตั้งแต่ Java 8) เช่นเดียวกับภาษาที่ใช้งานได้จัดเตรียมไว้เป็นเวลาหลายทศวรรษ
TheOperator

9

แหล่งที่มาของ String.valueOf แสดงสิ่งนี้:

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

ไม่ใช่ว่าจะสำคัญมาก แต่ฉันจะใช้ toString


9

แทนที่จะใช้ String.valueOf ฉันจะใช้. toString (); หลีกเลี่ยงการชกมวยอัตโนมัติบางรายการที่อธิบายโดย @ johnathan.holland

javadoc บอกว่า valueOf ส่งคืนค่าเดียวกันกับ Integer.toString ()

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

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

ตามที่ Tom Hawtin ชี้ให้เห็นในคำตอบที่ 'ชนะ' ไม่มีใครสามารถอินสแตนซ์ List <String> ได้เนื่องจากเป็นเพียงอินเทอร์เฟซเท่านั้น
Stu Thompson

ฉันรู้แล้ว เพียงแค่ฉันเขียนโค้ดโดยไม่ได้ลองใช้ ฉันจะแก้ไขในคำตอบของฉัน
ScArcher2

9

นี่คือวิธีแก้ปัญหาแบบซับเดียวโดยไม่ต้องโกงด้วยไลบรารีที่ไม่ใช่ JDK

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

7

โซลูชันอื่นโดยใช้ Guava และ Java 8

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

3

ไม่ใช่ Java หลักและไม่ใช่แบบทั่วไป แต่ไลบรารีคอลเลกชันจาการ์ตาคอมมอนส์ยอดนิยมมีเนื้อหาที่เป็นประโยชน์สำหรับงานประเภทนี้ โดยเฉพาะดูวิธีการรวบรวมบน

CollectionUtils

สิ่งที่ควรพิจารณาหากคุณใช้คอลเลกชันคอมมอนส์ในโครงการของคุณอยู่แล้ว


4
อย่าใช้ Apache Collections พวกนี้เก่าล้าสมัยไม่พิมพ์ปลอดภัยและเขียนไม่ดี
KitsuneYMG

3

ฝากถึงคนที่กังวลเรื่อง "มวย" ในคำตอบของ jsight: ไม่มีเลย String.valueOf(Object)ใช้ที่นี่และไม่มีการแกะกล่องintเคยทำการ

ไม่ว่าคุณจะใช้Integer.toString()หรือString.valueOf(Object)ขึ้นอยู่กับว่าคุณต้องการจัดการกับ null ที่เป็นไปได้อย่างไร คุณต้องการโยนข้อยกเว้น (อาจ) หรือมีสตริง "null" ในรายการของคุณ (อาจจะ) ถ้าอดีตคุณต้องการที่จะโยนNullPointerExceptionหรือประเภทอื่น ๆ ?

นอกจากนี้ข้อบกพร่องเล็กน้อยในการตอบสนองของ jsight: Listเป็นอินเทอร์เฟซคุณไม่สามารถใช้ตัวดำเนินการใหม่กับมันได้ ฉันอาจจะใช้java.util.ArrayListในกรณีนี้โดยเฉพาะอย่างยิ่งเมื่อเรารู้ล่วงหน้าว่ารายการน่าจะนานแค่ไหน



2

@ โจนาธาน: ฉันอาจเข้าใจผิด แต่ฉันเชื่อว่า String.valueOf () ในกรณีนี้จะเรียกใช้ฟังก์ชัน String.valueOf (Object) แทนที่จะทำให้กล่องเป็น String.valueOf (int) String.valueOf (Object) จะคืนค่า "null" หากเป็น null หรือเรียก Object.toString () หากไม่ใช่ null ซึ่งไม่ควรเกี่ยวข้องกับการชกมวย (แม้ว่าจะเห็นได้ชัดว่าการสร้างอินสแตนซ์อ็อบเจ็กต์สตริงใหม่เกี่ยวข้อง)


2

ฉันคิดว่าการใช้ Object.toString () เพื่อจุดประสงค์อื่นนอกเหนือจากการดีบักอาจเป็นความคิดที่ไม่ดีจริงๆแม้ว่าในกรณีนี้ทั้งสองจะมีฟังก์ชันเทียบเท่ากัน (สมมติว่ารายการไม่มีค่าว่าง) นักพัฒนามีอิสระที่จะเปลี่ยนลักษณะการทำงานของ toString () วิธีการใด ๆ โดยไม่มีคำเตือนใด ๆ รวมทั้ง toString () วิธีการของคลาสใด ๆ ในไลบรารีมาตรฐาน

ไม่ต้องกังวลกับปัญหาด้านประสิทธิภาพที่เกิดจากกระบวนการชกมวย / แกะกล่อง หากประสิทธิภาพเป็นสิ่งสำคัญเพียงแค่ใช้อาร์เรย์ ถ้ามันสำคัญมากอย่าใช้ Java การพยายามชิงไหวชิงพริบ JVM มี แต่จะทำให้ปวดใจ


2

คำตอบสำหรับผู้เชี่ยวชาญเท่านั้น:

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

วิธีนี้ใช้ได้ผล แต่เสียค่าใช้จ่ายจากการขาดประสิทธิภาพ Java Strings คือสองไบต์ต่อหนึ่งอักขระดังนั้น "," จึงเพิ่มต้นทุนคงที่สี่ไบต์ต่อจำนวนเต็มก่อนที่จะนับจำนวนเต็มนั้นเอง .... เหนือสิ่งอื่นใด
Robert Christian

ฉันคิดว่า regex อาจมีปัญหามากกว่าในแง่ของประสิทธิภาพวงจร CPU ดิบ ในแง่ของหน่วยความจำฉันเดาว่าการใช้งานที่สมเหตุสมผล (สมมติว่าการใช้งานที่ไม่สมเหตุสมผลของ "Sun" String) จะแชร์อาร์เรย์สำรองเดียวกัน (จากall) ดังนั้นหน่วยความจำจะค่อนข้างมีประสิทธิภาพซึ่งจะมีความสำคัญต่อประสิทธิภาพในระยะยาว เว้นแต่คุณต้องการเก็บองค์ประกอบอย่างใดอย่างหนึ่งไว้แน่นอน ...
Tom Hawtin - แท

2

Lambdajช่วยให้สามารถทำได้ด้วยวิธีที่ง่ายและอ่านได้ ตัวอย่างเช่นสมมติว่าคุณมีรายการจำนวนเต็มและคุณต้องการแปลงในการแทนค่าสตริงที่สอดคล้องกันคุณสามารถเขียนอะไรแบบนั้นได้

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 ใช้ฟังก์ชันการแปลงเฉพาะในขณะที่คุณทำซ้ำกับผลลัพธ์


1

คุณไม่สามารถหลีกเลี่ยง "มวยเหนือศีรษะ"; คอนเทนเนอร์ทั่วไป faux ของ Java สามารถจัดเก็บออบเจ็กต์ได้เท่านั้นดังนั้น ints ของคุณจะต้องใส่กล่องเป็นจำนวนเต็ม โดยหลักการแล้วมันสามารถหลีกเลี่ยงการดาวน์คาสต์จาก Object เป็น Integer ได้ (เนื่องจากไม่มีจุดหมายเนื่องจาก Object นั้นดีพอสำหรับทั้ง String.valueOf และ Object.toString) แต่ฉันไม่รู้ว่าคอมไพเลอร์ฉลาดพอที่จะทำเช่นนั้นหรือไม่ การแปลงจาก String เป็น Object ควรเป็น no-op ไม่มากก็น้อยดังนั้นฉันจะไม่กังวลเกี่ยวกับเรื่องนี้


คอมไพเลอร์ไม่ฉลาดพอที่จะทำเช่นนั้น เมื่อ javac ทำงานมันจะดึงข้อมูลประเภท generics ทั้งหมดออกไป การใช้งานคอลเลกชันยาสามัญจะจัดเก็บการอ้างอิงวัตถุเสมอ คุณสามารถละเว้นพารามิเตอร์ <T> และรับประเภท "raw" ได้ "List l = new List ()" เทียบกับ "List <String> l = new List <String> ()" แน่นอนว่านี่หมายความว่า "List <String> l = (List <String>) new List <Integer> ()" จะรวบรวมและเรียกใช้จริง ๆ แต่เห็นได้ชัดว่าอันตรายมาก
Dave Dopson

1

ฉันไม่เห็นวิธีแก้ปัญหาใด ๆ ที่เป็นไปตามหลักของความซับซ้อนของอวกาศ หากรายการจำนวนเต็มมีองค์ประกอบจำนวนมากก็เป็นปัญหาใหญ่

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

เราสามารถใช้ iterator เพื่อให้ได้สิ่งเดียวกัน

    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

การใช้สตรีม: หากให้บอกว่าผลลัพธ์เป็นรายการจำนวนเต็ม ( List<Integer> result) แล้ว:

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

วิธีหนึ่งในการแก้ปัญหา หวังว่านี่จะช่วยได้


1

วิธีแก้ปัญหาที่กระชับขึ้นเล็กน้อยโดยใช้วิธีการ forEach ในรายการเดิม:

    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

เพื่อความสนุกสนานวิธีแก้ปัญหาโดยใช้กรอบการรวมส้อม jsr166y ที่ควรจะเป็นใน JDK7

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

(ข้อจำกัดความรับผิดชอบ: ไม่รวบรวม Spec ไม่ได้สรุปเป็นต้น)

ไม่น่าจะอยู่ใน JDK7 เป็นการอนุมานประเภทเล็กน้อยและน้ำตาลสังเคราะห์เพื่อให้มีการจับคู่เรียก verbose น้อยลง:

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

0

นี่เป็นสิ่งพื้นฐานที่ต้องทำฉันจะไม่ใช้ไลบรารีภายนอก (จะทำให้เกิดการพึ่งพาในโครงการของคุณซึ่งคุณอาจไม่ต้องการ)

เรามีคลาสของวิธีการคงที่ที่สร้างขึ้นโดยเฉพาะเพื่อทำงานประเภทนี้ เนื่องจากโค้ดนี้ง่ายมากเราจึงปล่อยให้ Hotspot ทำการเพิ่มประสิทธิภาพให้เรา ดูเหมือนว่าจะเป็นธีมในโค้ดของฉันเมื่อเร็ว ๆ นี้: เขียนโค้ดที่เรียบง่าย (ตรงไปตรงมา) และปล่อยให้ Hotspot ทำสิ่งมหัศจรรย์ เราไม่ค่อยมีปัญหาด้านประสิทธิภาพเกี่ยวกับโค้ดเช่นนี้ - เมื่อ VM เวอร์ชันใหม่มาพร้อมคุณจะได้รับสิทธิประโยชน์ความเร็วพิเศษทั้งหมดเป็นต้น

เท่าที่ฉันชอบคอลเลกชันจาการ์ตาพวกเขาไม่รองรับ Generics และใช้ 1.4 เป็น LCD ฉันระวัง Google Collections เพราะถูกระบุว่าเป็นระดับการสนับสนุน Alpha!


-1

ฉันแค่อยากจะตีระฆังด้วยวิธีแก้ปัญหาเชิงวัตถุ

หากคุณสร้างโมเดลอ็อบเจ็กต์โดเมนโซลูชันจะอยู่ในอ็อบเจ็กต์โดเมน โดเมนที่นี่คือรายการของจำนวนเต็มที่เราต้องการค่าสตริง

วิธีที่ง่ายที่สุดคืออย่าแปลงรายการเลย

ตามที่กล่าวไว้เพื่อที่จะแปลงโดยไม่ต้องแปลงให้เปลี่ยนรายการจำนวนเต็มเดิมเป็นรายการมูลค่าโดยที่ค่ามีลักษณะดังนี้ ...

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

ซึ่งจะเร็วกว่าและใช้หน่วยความจำน้อยกว่าการคัดลอกรายการ

โชคดี!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.