Cách tạo danh sách mới với thuộc tính của một đối tượng nằm trong danh sách khác


79

Hãy tưởng tượng rằng tôi có một danh sách các đối tượng nhất định:

List<Student>

Và tôi cần phải tạo ra một danh sách khác kể cả idscủa Studentstrong danh sách trên:

List<Integer>

Tránh sử dụng vòng lặp, liệu có thể đạt được điều này bằng cách sử dụng bộ sưu tập apache hoặc ổi không?

Phương pháp nào hữu ích cho trường hợp của tôi?


Này, tôi thấy nó chỉ là bây giờ: stackoverflow.com/questions/737244/...
Javatar

Câu trả lời của Jon khá hay nhưng nếu bạn để ý thì nó cũng sử dụng một vòng lặp. Bất kỳ giải pháp nào sẽ sử dụng một vòng lặp - mặc dù nó có thể không được hiển thị cho bạn, nhưng trong nội bộ nó sẽ
Hage

ai đó phải áp dụng vòng lặp để hoàn thành nó. hoặc bạn hoặc một số lib mà bạn có thể sử dụng.
sudmong

Thực ra câu trả lời của Jon không phù hợp với hoàn cảnh của tôi ở chỗ tôi không muốn sử dụng vòng lặp for. Tôi nghĩ rằng có một cách thuận tiện hơn so với ở đâu đó nhưng Waitin cho tôi để tìm thấy nó :)
Javatar

Câu trả lời:


173

Cách thực hiện trong Java 8: -

List<Integer> idList = students.stream().map(Student::getId).collect(Collectors.toList());

1
Điều gì sẽ xảy ra nếu tôi muốn có một danh sách các bộ giá trị? Một cái gì đó như [(Id, tên), (Id, tên)].
Khazana

Không phải tất cả các tính năng 1.8 đều được hỗ trợ cho tất cả các API Android. Đặc biệt, java.util.stream không được hỗ trợ cho đến API 24.
The Black Horse

41

Với Guava, bạn có thể sử dụng Chức năng như -

private enum StudentToId implements Function<Student, Integer> {
        INSTANCE;

        @Override
        public Integer apply(Student input) {
            return input.getId();
        }
    }

và bạn có thể sử dụng chức năng này để chuyển đổi Danh sách sinh viên thành các id như -

Lists.transform(studentList, StudentToId.INSTANCE);

Chắc chắn nó sẽ lặp lại để trích xuất tất cả id, nhưng hãy nhớ các phương thức ổi trả về chế độ xem và Hàm sẽ chỉ được áp dụng khi bạn cố gắng lặp lại List<Integer>
nếu bạn không lặp, nó sẽ không bao giờ áp dụng vòng lặp.

Lưu ý: Hãy nhớ đây là dạng xem và nếu bạn muốn lặp lại nhiều lần, tốt hơn là sao chép nội dung trong một số List<Integer>như

ImmutableList.copyOf(Iterables.transform(students, StudentToId.INSTANCE));

Tôi nghĩ rằng thật không phù hợp khi phải xác định một chức năng riêng biệt. Tôi nghĩ rằng điều này cũng có thể được thực hiện ẩn danh và trong một quy trình một bước
Marc

làm thế nào để bạn trích xuất các thành viên chuỗi (float, v.v.) của Danh sách?
sepehr

22

Cảm ơn Premraj cho tùy chọn thú vị thay thế, được ủng hộ .

Tôi đã sử dụng apache CollectionUtils và BeanUtils. Theo đó, tôi hài lòng với hiệu suất của mã sau:

List<Long> idList = (List<Long>) CollectionUtils.collect(objectList, 
                                    new BeanToPropertyValueTransformer("id"));

Điều đáng nói là, tôi sẽ so sánh hiệu suất của ổi ( Premraj cung cấp) và collectionUtils mà tôi đã sử dụng ở trên, và quyết định cái nào nhanh hơn.


3
Tôi sẽ thích ổi trên apache bộ sưu tập không phụ thuộc vào hiệu suất vì những lý do như thế nào - hiện đại hơn, Generics, không sử dụng phản ánh cho biến đổi, vv ổi Nói chung là xa hiện đại hơn mà apache bộ sưu tập - đọc thêm ở đây
Premraj

1
Có, nhưng thực ra có vẻ không phải là một ý kiến ​​hay đối với tôi khi hạn chế việc sử dụng nó bởi nhu cầu bắt buộc phải khai báo thêm enum cho mỗi loại đối tượng mà tôi muốn chuyển đổi.
Javatar 11/12/12

Nó phụ thuộc vào thiết kế của bạn - Bạn có thể có giao diện cho biết phương pháp Identifiablenào xác định getId()và sau đó bạn có thể sử dụng mẫu đơn enum đơn này để trích xuất Id thường thấy.
Premraj

2
ổi chắc chắn là hiệu quả hơn Bean utils như những ứng dụng phản xạ sau ..
Ravi

2
Sử dụng tên thuộc tính làm Chuỗi trong phương thức khởi tạo mới BeanToPropertyValueTransformer ("id") là điều tôi chắc chắn cố gắng tránh. Tái cấu trúc sẽ rất khó! Nhưng tôi đang tìm giải pháp để giải quyết vấn đề này. Trong khi đó, tôi sẽ đi với giải pháp Ổi, dài dòng nhưng an toàn.
redochka

7

Giải pháp biểu thức lambda Java 8:

List<Integer> iDList = students.stream().map((student) -> student.getId()).collect(Collectors.toList());

Nếu Java <1.8 thì hãy sử dụng Apache CollectionUtils. Ví dụ: Collection <String> firstnames = CollectionUtils.collect (danh sách người dùng, TransformerUtils.invokerTransformer ("getFirstname"));
a_subscriber

5

Nếu ai đó đến đây sau vài năm:

List<String> stringProperty = (List<String>) CollectionUtils.collect(listOfBeans, TransformerUtils.invokerTransformer("getProperty"));

Và bạn chỉ cứu tôi :)
Behrad3d

-5

Về mặt toán học, không thể thực hiện điều này nếu không có vòng lặp. Để tạo một ánh xạ, F, của một tập giá trị rời rạc với một tập giá trị rời rạc khác, F phải hoạt động trên mỗi phần tử trong tập ban đầu. (Về cơ bản, cần có một vòng lặp để làm điều này.)

Điều đó đang được nói:

Tại sao bạn cần một danh sách mới? Bạn có thể tiếp cận bất kỳ vấn đề nào bạn đang giải quyết theo cách sai.

Nếu bạn có một danh sách Student, thì bạn chỉ còn một hoặc hai bước nữa, khi lặp qua danh sách này, từ việc lặp qua số ID của học sinh.

for(Student s : list)
{
    int current_id = s.getID();
    // Do something with current_id
}

Nếu bạn gặp một loại vấn đề khác, hãy bình luận / cập nhật câu hỏi và chúng tôi sẽ cố gắng giúp bạn.


Đầu tiên, cảm ơn đã trả lời của bạn. Tuy nhiên, điều đáng ngạc nhiên là bạn nói cần một danh sách mới là sai cách. Bởi vì nó là phụ thuộc vào công suất và phạm vi của nhu cầu. Do đó, cách tiếp cận của bạn là sai lầm :) Một lần nữa, đề cập của tôi về "khả năng đạt được điều đó mà không cần vòng lặp" là về một cách thuận tiện hơn để không làm cho mã không thể đọc được và hiệu suất thấp. Dù sao, tôi đã tìm ra cách để đạt được nó, sẽ chia sẻ một chút.
Javatar

Tôi không nói rằng đó cách sai, nhưng nó có thể là cách sai, tùy thuộc vào vấn đề bạn đang cố gắng giải quyết.
Zéychin
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.