2008-08-20 57 views
83

Tôi có 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 bằng List<String> mới.Danh sách chuyển đổi <Integer> thành Danh sách <String>

Đương nhiên, tôi có thể tạo ra một vòng lặp mới List<String> và thông qua Danh mục yêu cầu String.valueOf() cho mỗi số nguyên, nhưng tôi đã tự hỏi nếu có một tốt hơn (đọc: tự động hơn) cách để làm việc đó?

Trả lời

64

Theo như tôi biết, lặp lại và khởi tạo là cách duy nhất để thực hiện việc này. Một cái gì đó tương tự (ví người khác giúp đỡ tiềm năng, vì tôi chắc chắn rằng bạn biết làm thế nào để 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<String>(oldList.size()) 
for (Integer myInt : oldList) { 
    newList.add(String.valueOf(myInt)); 
} 
+0

Khi đơn giản, điều này được gọi là làm đẹp. – Elbek

+1

Các poster ban đầu dường như chỉ ra rằng ông đã nghĩ về điều này nhưng được coi là giải pháp này quá phức tạp hoặc tẻ nhạt. Nhưng tôi khó ép để tưởng tượng những gì có thể dễ dàng hơn. Có, đôi khi bạn phải viết 3 hoặc 4 dòng mã để hoàn thành công việc. – Jay

+0

Nhưng điều đó liên kết bạn với ArrayList. Điều này có thể được thực hiện bằng cách sử dụng cùng một triển khai như danh sách gốc không? –

2

@ Jonathan: Tôi có thể bị nhầm lẫn, nhưng tôi tin rằng String.valueOf() trong trường hợp này sẽ gọi hàm String.valueOf (Object) thay vì nhận đượ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 null, không liên quan đến boxing (mặc dù rõ ràng là instantiating các đối tượng chuỗi mới có liên quan).

9

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

javadoc nói rằng valueOf trả về cùng một thứ như Integer.toString().

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

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

như được chỉ ra bởi Tom Hawtin trong câu trả lời 'chiến thắng', một ví dụ không thể liệt kê vì nó chỉ là một giao diện. –

+0

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

2

Tôi nghĩ rằng sử dụng Object.ToString() cho bất kỳ mục đích nào khác hơn là gỡ lỗi có lẽ là một ý tưởng thực sự xấu, mặc dù trong trường hợp này hai có chức năng tương đương (giả sử trong 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, bao gồm các phương thức toString() của bất kỳ lớp nào trong thư viện chuẩn.

Đừng lo lắng về các vấn đề về hiệu suất gây ra bởi quá trình boxing/unboxing. Nếu hiệu suất là rất quan trọng, chỉ cần sử dụng một mảng. Nếu nó thực sự quan trọng, không sử dụng Java. Cố gắng để outsmart JVM sẽ chỉ dẫn đến đau khổ.

+0

+1 cho "đau lòng" ... – Smalltown2k

9

Nguồn cho String.valueOf thấy điều này:

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

Không phải là nó quan trọng hơn nhiều, nhưng tôi sẽ sử dụng toString.

1

Bạn không thể tránh "chi phí đấm bốc"; Các thùng chứa chung 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 gói thành các số nguyên. Về nguyên tắc nó có thể tránh downcast từ Object đến Integer (vì nó là vô nghĩa, bởi 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 đó không. Việc chuyển đổi từ String thành Object phải nhiều hơn hoặc ít hơn một không-op, vì vậy tôi sẽ bị phân biệt lo lắng về điều đó.

+0

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ả các thông tin kiểu generics. Việc thực hiện cơ bản của một bộ sưu tập Generics ALWAYS lưu trữ các tham chiếu Object. Bạn thực sự có thể bỏ qua các parametrization và nhận được một loại "nguyên". "Danh sách l = Danh sách mới()" so với "Danh sách l = Danh sách mới ()".tất nhiên, điều này có nghĩa là "Danh sách l = (Danh sách ) Danh sách mới ()" sẽ thực sự biên dịch và chạy, nhưng rõ ràng là rất nguy hiểm. –

3

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

CollectionUtils

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

+4

Không bao giờ sử dụng Bộ sưu tập Apache. Chúng cũ, lỗi thời, không an toàn, và được viết kém. – KitsuneYMG

39

Điều bạn đang làm là tốt, nhưng nếu bạn cảm thấy cần phải 'Java-it-up', bạn có thể sử dụng Transformercollect method 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); 
+0

wow, những thứ tuyệt vời! – Verhogen

+1

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

+5

Trừ khi công việc mới đã được thực hiện trên bộ sưu tập apache, họ không làm generics. – KitsuneYMG

3

Đối với những lo ngại về "đấm bốc" trong câu trả lời của jsight: chẳng có ai. String.valueOf(Object) được sử dụng ở đây và không có hộp unboxing nào để int được thực hiện.

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

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

2

Một câu trả lời cho chỉ 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); 
+0

Điều này hoạt động nhưng với chi phí không hiệu quả. Java Strings là hai byte cho mỗi char, do đó, "," thêm một chi phí cố định bốn byte cho mỗi số nguyên trước khi đếm số nguyên chính nó .... trong số những thứ khác. –

+0

Tôi nghĩ rằng regex có thể là một vấn đề hơn về hiệu quả chu kỳ CPU nguyên. Về mặt bộ nhớ, tôi đoán việc triển khai thực hiện hợp lý (giả sử "thực hiện" Mặt trời "không hợp lý") sẽ chia sẻ cùng một mảng sao lưu (từ 'tất cả'), vì vậy sẽ thực sự hiệu quả với bộ nhớ, điều này rất 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 các yếu tố của khóa học ... –

0

Just for fun, một giải pháp sử dụng jsr166y ngã ba-gia khuôn khổ đó nên 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(); 

(Disclaimer:.. Không biên soạn Spec không hoàn thiện vv)

khó có thể trong JDK7 là một chút suy luận kiểu và đường cú pháp để làm cho rằng cuộc gọi withMapping ít tiết:

.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 một thư viện bên ngoài (nó sẽ gây ra một sự phụ thuộc trong dự án của bạn mà bạn có thể không cần).

Chúng tôi có một lớp phương pháp tĩnh được chế tác cụ thể để thực hiện các loại công việc này. Bởi vì mã cho việc này rất đơn giản nên chúng tôi cho phép Hotspot thực hiện tối ưu hóa cho chúng tôi. Điều này có vẻ 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à để cho Hotspot làm phép thuật của nó. Chúng tôi hiếm khi có các vấn đề về hiệu năng xung quanh mã như thế này - khi phiên bản VM mới xuất hiện cùng bạn nhận được tất cả các lợi ích tốc độ bổ sung, v.v.

Nhiều như tôi yêu bộ sưu tập Jakarta, 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 Google Bộ sưu tập vì chúng được liệt kê là cấp hỗ trợ Alpha!

82

Sử dụng Google Collections from Guava-Project, bạn có thể sử dụng phương pháp transform trong lớp 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()); 

Các List trả về bởi transform là một xem vào danh sách ủng hộ - việc chuyển đổi sẽ được áp dụng trên mỗi truy cập vào các biến đổi danh sách.

Lưu ý rằng Functions.toStringFunction() sẽ ném NullPointerException khi được áp dụng cho giá trị rỗng, vì vậy, chỉ sử dụng nếu bạn chắc chắn danh sách của mình sẽ không chứa giá trị rỗng.

+1

Sẽ tốt hơn nếu có nhiều 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 .. 1 chức năng gọi thêm cho mỗi giá trị? – h3xStream

+3

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

2

Lambdaj cho phép thực hiện điều đó theo cách rất đơn giản và dễ đọc.Ví dụ, giả sử bạn có một danh sách của Integer và bạn muốn chuyển đổi chúng trong biểu diễn String tương ứng, bạn có thể viết một cái gì đó như thế;

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 chức năng chuyển đổi khi bạn đang lặp lại kết quả.

8

Đây là giải pháp một lớp 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(", ")); 
+0

+1 vì lợi ích hack tinh khiết. – metasim

-1

Tôi chỉ muốn kêu gọi giải pháp hướng đối tượng cho vấn đề.

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

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

Nói như vậy, để chuyển đổi mà không chuyển đổi, thay đổi danh sách ban đầu của Integer vào danh sách của giá trị gia tăng, trong đó giá trị gia tăng trông giống như thế này ...

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

này sẽ nhanh hơn và chiếm ít bộ nhớ hơn là sao chép Danh sách.

Chúc may mắn!

52

Giải pháp cho Java 8. Dài hơn một chút so với dung lượng Ổi, 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()); 
+0

Trong khi điều này là lâu hơn một chút cho ví dụ 'toString', nó kết thúc ngắn hơn đối với các chuyển đổi không được thư viện hàm của Guava hỗ trợ. Chức năng tùy chỉnh vẫn dễ dàng, nhưng nó là mã nhiều hơn đáng kể sau đó luồng Java 8 này – lightswitch05

5

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

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

Tôi không thấy bất kỳ giải pháp đó là sau khi chủ yếu của không gian phức tạp. Nếu danh sách các số nguyên có số lượng lớn các phần tử 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 tôi 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(); 
    } 
Các vấn đề liên quan