Chuyển đổi danh sách <Integer> thành danh sách <chuỗi>


105

Tôi có một danh sách các số nguyên List<Integer>và tôi muốn chuyển đổi tất cả các đối tượng số nguyên thành Chuỗi, do đó kết thúc với một mới List<String>.

Đương nhiên, tôi có thể tạo một mới List<String>và lặp qua danh sách gọi String.valueOf()cho mỗi số nguyên, nhưng tôi tự hỏi liệu có cách nào tốt hơn (đọc: tự động hơn ) không?

Câu trả lời:


77

Theo như tôi biết, lặp lại và khởi tạo là cách duy nhất để làm điều này. Một cái gì đó như (cho những người khác tiềm năng trợ giúp, vì tôi chắc rằng bạn biết cách làm điều này):

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

Khi Nó là đơn giản, đây được gọi là vẻ đẹp.
Elbek

1
Người đăng ban đầu dường như chỉ ra rằng anh ta đã nghĩ đến điều này nhưng cho rằng giải pháp này quá phức tạp hoặc tẻ nhạt. Nhưng tôi khó tưởng tượng điều gì có thể dễ dàng hơn. Vâng, đôi khi bạn phải viết 3 hoặc 4 dòng mã để hoàn thành công việc.
Jay

Nhưng điều đó ràng buộc bạn với ArrayList. Điều này có thể được thực hiện bằng cách sử dụng triển khai giống như danh sách ban đầu?
alianos-

@Andreas oldList.getClass (). NewInstance () sẽ thực hiện
Lluis Martinez

96

Sử dụng Bộ sưu tập của Google từ Guava-Project , bạn có thể sử dụng transformphương pháp trong lớp Danh sách

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

Trả Listvề transformlà một chế độ xem trên danh sách sao lưu - phép biến đổi sẽ được áp dụng trên mỗi lần truy cập vào danh sách được chuyển đổi.

Hãy lưu ý rằng nó Functions.toStringFunction()sẽ ném một NullPointerExceptionkhi áp dụng cho null, vì vậy chỉ sử dụng nó nếu bạn chắc chắn rằng danh sách của bạn sẽ không chứa null.


1
Nó sẽ được tốt đẹp nếu có những chức năng sẵn sàng hơn bên cạnh Functions.toStringFunction ()
ThiamTeck

1
sạch nhưng có thể không nhanh bằng .. 1 lệnh gọi hàm bổ sung cho mỗi giá trị?
h3xStream

3
HotSpot có thể nội tuyến các cuộc gọi hàm - vì vậy nếu nó được gọi là đủ, nó sẽ không tạo ra sự khác biệt.
Ben Lings

3
Tôi không tán thành điều này vì nó thực sự là một giải pháp. Nhưng khuyến khích mọi người thêm phụ thuộc vào thư viện để giải quyết công việc đơn giản như vậy là điều không nên đối với tôi.
estani

1
Giải pháp tuyệt vời nếu bạn đang sử dụng Guava trong giải pháp của chúng tôi.
dudinha-debalus

86

Giải pháp cho Java 8. Dài hơn một chút so với Guava, nhưng ít nhất bạn không phải cài đặt thư viện.

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
Mặc dù toStringví dụ này dài hơn một chút , nhưng nó sẽ ngắn hơn đối với các chuyển đổi không được thư viện Chức năng của Guava hỗ trợ. Chức năng tùy chỉnh vẫn là dễ dàng, nhưng nó là đáng kể nhiều mã thì đây dòng Java 8
lightswitch05

40

Những gì bạn đang làm là ổn, nhưng nếu bạn cảm thấy cần phải 'Java-it-up', bạn có thể sử dụng Transformerphương thức thu thập từ Apache Commons , ví dụ:

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

..và sau đó..

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

1
CollectionUtils.collect (collectionOfIntegers, new org.apache.commons.collections.functors.StringValueTransformer ()); Nhưng, StringValueTransformer sử dụng String.valueOf ...
Kannan Ekanath

5
Trừ khi công việc mới đã được thực hiện trên các bộ sưu tập apache, nếu không chúng không thực hiện chung chung.
KitsuneYMG

1
Đây thực sự là một Java-ing-it down. Đây không phải là Java thành ngữ, và giống như lập trình hàm hơn. Có thể khi chúng ta nhận được các bao đóng trong Java 8, bạn có thể gọi nó là Java thành ngữ.
Christoffer Hammarström

Bạn chắc chắn muốn sử dụng Bộ sưu
tập4

Định nghĩa một lớp mới chỉ để "OOP hơn hoặc có tính thành ngữ" ... Tôi không thấy cách này tốt hơn vòng lặp for-each đơn giản như thế nào. Nó yêu cầu nhiều mã hơn và di chuyển chức năng đi (điều này có thể được giảm thiểu bởi các lớp ẩn danh, nhưng vẫn vậy). Kiểu hàm này chỉ bắt đầu trở nên hữu ích khi có một cú pháp phù hợp (tức là các biểu thức lambda kể từ Java 8), giống như các ngôn ngữ hàm đã cung cấp nó trong nhiều thập kỷ.
TheOperator

9

Nguồn cho String.valueOf hiển thị điều này:

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

Nó không quan trọng lắm, nhưng tôi sẽ sử dụng toString.


9

Thay vì sử dụng String.valueOf tôi muốn sử dụng .toString (); nó tránh một số quyền tự động được mô tả bởi @ johnathan.holland

Javadoc nói rằng valueOf trả về điều tương tự như Integer.toString ().

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

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

như Tom Hawtin đã chỉ ra trong câu trả lời 'chiến thắng', người ta không thể ví dụ Danh sách <Chuỗi> vì nó chỉ là một giao diện.
Stu Thompson

Heh, tôi biết điều đó. Chỉ là tôi đã viết mã mà không thử nó. Tôi sẽ sửa nó trong câu trả lời của tôi.
ScArcher2 15/09/08

9

Đây là giải pháp một lớp mà không gian lận với thư viện không phải JDK.

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

7

Một giải pháp khác sử dụng Guava và Java 8

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

3

Không phải Java cốt lõi, và không phải là ified chung chung, nhưng thư viện bộ sưu tập commons Jakarta phổ biến có một số trừu tượng hữu ích cho loại nhiệm vụ này. Cụ thể, hãy xem các phương pháp thu thập trên

CollectionUtils

Một cái gì đó cần xem xét nếu bạn đã sử dụng bộ sưu tập commons trong dự án của mình.


4
Không bao giờ sử dụng Apache Collections. Chúng đã cũ, lỗi thời, không an toàn về kiểu chữ và viết kém.
KitsuneYMG

3

Đối với những người lo ngại về "quyền anh" trong câu trả lời của jsight: không có. String.valueOf(Object)được sử dụng ở đây và không intbao giờ thực hiện mở hộp cho .

Cho dù bạn sử dụng Integer.toString()hay String.valueOf(Object)phụ thuộc vào cách bạn muốn xử lý các giá trị null. Bạn có muốn ném một ngoại lệ (có thể), hoặc có Chuỗi "null" trong danh sách của bạn (có thể). Nếu trước đây, bạn có muốn ném một NullPointerExceptionhoặc một số loại khác?

Ngoài ra, một lỗ hổng nhỏ trong phản hồi của jsight: Listlà giao diện, bạn không thể sử dụng toán tử mới trên đó. Tôi có thể sẽ sử dụng một java.util.ArrayListtrong trường hợp này, đặc biệt là vì chúng tôi biết trước danh sách có khả năng dài bao lâu.


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

2

@Jonathan: Tôi có thể nhầm, nhưng tôi tin rằng String.valueOf () trong trường hợp này sẽ gọi hàm String.valueOf (Object) hơn là được đóng hộp thành String.valueOf (int). String.valueOf (Object) chỉ trả về "null" nếu nó là null hoặc gọi Object.toString () nếu không phải null, điều này không liên quan đến quyền anh (mặc dù rõ ràng việc khởi tạo các đối tượng chuỗi mới có liên quan).


2

Tôi nghĩ rằng việc sử dụng Object.toString () cho bất kỳ mục đích nào khác ngoài gỡ lỗi có lẽ là một ý tưởng thực sự tồi, mặc dù trong trường hợp này cả hai tương đương về mặt chức năng (giả sử danh sách không có null). Các nhà phát triển có thể tự do thay đổi hành vi của bất kỳ phương thức toString () nào mà không có bất kỳ cảnh báo nào, kể cả các phương thức toString () của bất kỳ lớp nào trong thư viện chuẩn.

Thậm chí đừng lo lắng về các vấn đề hiệu suất do quá trình boxing / unboxing gây ra. Nếu hiệu suất là quan trọng, chỉ cần sử dụng một mảng. Nếu nó thực sự quan trọng, đừng sử dụng Java. Cố gắng vượt qua JVM sẽ chỉ dẫn đến đau lòng.


2

Một câu trả lời chỉ dành cho các chuyên gia:

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

Điều này có hiệu quả nhưng phải trả giá là không hiệu quả. Chuỗi Java là hai byte cho mỗi ký tự, do đó, "," thêm một chi phí cố định bốn byte cho mỗi số nguyên trước khi đếm chính số nguyên .... trong số những thứ khác.
Robert Christian

Tôi nghĩ rằng regex có thể là một vấn đề hơn về hiệu quả chu kỳ CPU thô. Về bộ nhớ, tôi đoán một triển khai hợp lý (giả sử triển khai không hợp lý "Sun" String) sẽ chia sẻ cùng một mảng hỗ trợ (từ all), do đó thực sự sẽ thực sự khá hiệu quả về bộ nhớ, điều này sẽ quan trọng đối với hiệu suất lâu dài. Trừ khi bạn chỉ muốn giữ một trong những yếu tố tất nhiên ...
Tom Hawtin - tackline

2

Lambdaj cho phép làm điều đó một cách rất đơn giản và dễ đọc. Ví dụ: giả sử bạn có một danh sách các Số nguyên và bạn muốn chuyển đổi chúng trong biểu diễn Chuỗi tương ứng, bạn có thể viết một cái gì đó như vậy;

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 chỉ áp dụng hàm chuyển đổi khi bạn đang lặp lại kết quả.


1

Bạn không thể tránh khỏi "quyền anh trên không"; Các bộ chứa chung chung faux của Java chỉ có thể lưu trữ các Đối tượng, vì vậy các int của bạn phải được đóng hộp thành Số nguyên. Về nguyên tắc, nó có thể tránh downcast từ Object sang Integer (vì nó vô nghĩa, vì Object đủ tốt cho cả String.valueOf và Object.toString) nhưng tôi không biết liệu trình biên dịch có đủ thông minh để làm điều đó hay không. Việc chuyển đổi từ Chuỗi thành Đối tượng ít nhiều phải là không có, vì vậy tôi sẽ không muốn lo lắng về điều đó.


trình biên dịch KHÔNG đủ thông minh để làm điều đó. Khi javac chạy, nó thực sự loại bỏ tất cả thông tin loại chung. Việc triển khai cơ bản của một bộ sưu tập generics LUÔN LUÔN lưu trữ các tham chiếu Đối tượng. Bạn thực sự có thể bỏ qua tham số <T> và nhận loại "thô". "Danh sách l = new Danh sách ()" so với "Danh sách <Chuỗi> l = Danh sách mới <Chuỗi> ()". tất nhiên, điều này có nghĩa là "List <String> l = (List <String>) new List <Integer> ()" sẽ thực sự biên dịch và chạy, nhưng rõ ràng là rất nguy hiểm.
Dave Dopson

1

Tôi không thấy bất kỳ giải pháp nào tuân theo nguyên tắc phức tạp của không gian. Nếu danh sách các số nguyên có số lượng phần tử lớn thì đó là vấn đề lớn.

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

Chúng ta có thể sử dụng trình lặp để đạt được điều tương tự.

    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

Sử dụng Luồng: Nếu giả sử kết quả là danh sách các số nguyên ( List<Integer> result) thì:

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

Một trong những cách để giải quyết nó. Hi vọng điêu nay co ich.


1

Một giải pháp ngắn gọn hơn một chút bằng cách sử dụng phương thức forEach trong danh sách ban đầu:

    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

Chỉ cho vui thôi, một giải pháp sử dụng khuôn khổ tham gia fork jsr166y nên có trong 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();

(Tuyên bố từ chối trách nhiệm: Chưa được biên dịch. Thông số kỹ thuật chưa được hoàn thiện. Vv.)

Có vẻ như không có trong JDK7 là một chút suy luận kiểu và đường cú pháp để làm cho điều đó với lệnh gọiMapping ít dài dòng hơn:

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

0

Đây là một điều cơ bản để làm Tôi sẽ không sử dụng thư viện bên ngoài (nó sẽ gây ra sự phụ thuộc trong dự án của bạn mà bạn có thể không cần).

Chúng ta có một lớp các phương thức tĩnh được tạo riêng để thực hiện những công việc này. Bởi vì mã cho việc này rất đơn giản, chúng tôi để Hotspot thực hiện việc tối ưu hóa cho chúng tôi. Đây dường như là một chủ đề trong mã của tôi gần đây: viết mã rất đơn giản (đơn giản) và để Hotspot làm điều kỳ diệu của nó. Chúng tôi hiếm khi gặp vấn đề về hiệu suất xung quanh mã như thế này - khi một phiên bản VM mới xuất hiện, bạn sẽ nhận được tất cả các lợi ích bổ sung về tốc độ, v.v.

Tôi yêu thích các bộ sưu tập của Jakarta nhiều như vậy, chúng không hỗ trợ Generics và sử dụng 1.4 làm màn hình LCD. Tôi cảnh giác với Bộ sưu tập của Google vì chúng được liệt kê là cấp hỗ trợ Alpha!


-1

Tôi chỉ muốn nói với một giải pháp hướng đối tượng cho vấn đề.

Nếu bạn mô hình hóa các đối tượng miền, thì giải pháp nằm trong các đối tượng miền. Miền ở đây là Danh sách các số nguyên mà chúng ta muốn các giá trị chuỗi.

Cách dễ nhất là hoàn toàn không chuyển đổi danh sách.

Điều đó đang được nói, để chuyển đổi mà không cần chuyển đổi, hãy thay đổi danh sách Số nguyên ban đầu thành Danh sách Giá trị, trong đó Giá trị trông giống như thế này ...

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

Điều này sẽ nhanh hơn và chiếm ít bộ nhớ hơn so với việc sao chép Danh sách.

Chúc may mắn!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.