Jak utworzyć nową listę z właściwością obiektu znajdującego się na innej liście


81

Wyobraź sobie, że mam listę pewnych obiektów:

List<Student>

Muszę wygenerować kolejną listę zawierającą elementy idsz Studentspowyższej listy:

List<Integer>

Unikając pętli, czy można to osiągnąć za pomocą kolekcji apache lub guawy ?

Które metody powinny być przydatne w moim przypadku?


Hej, znalazłem to właśnie teraz: stackoverflow.com/questions/737244/…
— Javatar

Odpowiedź Jona jest całkiem fajna, ale jeśli spojrzysz na nią, również używa pętli. Każde rozwiązanie wykorzysta pętlę - chociaż może nie być dla ciebie widoczna, ale wewnętrznie będzie
— hage

ktoś musi zastosować pętlę, aby to zrobić. Ty lub jakaś biblioteka, której możesz użyć.
— sudmong

Właściwie odpowiedź jona nie pasuje do mojej sytuacji, ponieważ nie chcę używać pętli for. Myślę, że jest gdzieś wygodniejszy sposób, ale czekam, aż go znajdę :)
— Javatar

Odpowiedzi:


175

Java 8 jak to zrobić: -

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

2
A jeśli chcę listę krotek? Coś w rodzaju [(Id, imię), (Id, imię)].
— Coder95,

Nie wszystkie funkcje wersji 1.8 są obsługiwane dla wszystkich interfejsów API systemu Android. W szczególności java.util.stream nie jest obsługiwany do API 24.
— The Black Horse

41

Dzięki guawie możesz użyć funkcji, takich jak -

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

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

i możesz użyć tej funkcji do konwersji listy uczniów na identyfikatory, takie jak -

Lists.transform(studentList, StudentToId.INSTANCE);

Z pewnością zapętli się, aby wyodrębnić wszystkie identyfikatory, ale pamiętaj, że metody guawy zwracają widok, a funkcja zostanie zastosowana tylko wtedy, gdy spróbujesz iterować po List<Integer>
pętli Jeśli nie wykonasz iteracji, nigdy nie zastosuje pętli.

Uwaga: Pamiętaj, to jest widok, a jeśli chcesz iteracyjne wiele razy, że będzie lepiej, aby skopiować zawartość w jakiś inny List<Integer>podobny

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

Myślę, że oddzielne definiowanie funkcji jest nieeleganckie. Myślę, że można to również zrobić anonimowo i jednoetapowo
— Marc,

jak wyodrębnić elementy będące ciągami znaków (float itp.) z listy?
— wrzesień

22

Dzięki Premraj za alternatywną opcję fajną, przegłosowaną.

Użyłem apache CollectionUtils i BeanUtils. W związku z tym jestem zadowolony z działania następującego kodu:

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

Warto wspomnieć, że porównuję wydajność guawy ( dostarczonej przez Premraj ) z narzędziami z kolekcji, których użyłem powyżej i zdecyduję, która z nich jest szybsza.


3
Wolę guawa od kolekcji apaczów, niezależnie od wydajności z powodów takich jak - bardziej nowoczesne, generyczne, nie używają odbić do transformacji itp. Ogólnie guawa jest znacznie bardziej nowoczesna niż kolekcje
— apaszów

1
Tak, ale w rzeczywistości nie wydaje mi się dobrym pomysłem ograniczanie jego użycia przez obowiązkową potrzebę dodatkowej deklaracji wyliczenia dla każdego typu obiektu, który chcę przekształcić.
— Javatar

Cóż, to zależy od twojego projektu - możesz mieć interfejs, Identifiablektóry mówi, który definiuje getId()metodę, a następnie możesz użyć tego pojedynczego wzorca pojedynczego wyliczenia, aby zwykle wyodrębnić Id.
— Premraj

2
guawa jest zdecydowanie bardziej wydajna niż narzędzia Bean, ponieważ później wykorzystuje odbicia ..
— ravi

2
Używanie nazwy właściwości jako String w konstruktorze new BeanToPropertyValueTransformer ("id") jest czymś, czego zdecydowanie staram się unikać. Refaktoryzacja będzie trudna! Ale szukam rozwiązania, aby to obejść. W międzyczasie zdecyduję się na rozwiązanie Guava, rozwlekłe, ale bezpieczne.
— redochka

7

Rozwiązanie wyrażenia lambda Java 8:

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

Jeśli Java <1.8, użyj Apache CollectionUtils. Przykład: Collection <String> firstnames = CollectionUtils.collect (userlist, TransformerUtils.invokerTransformer ("getFirstname"));
— a_subscriber

5

Jeśli ktoś dotrze tu po kilku latach:

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

I właśnie mnie uratowałeś :)
— Behrad3d

-5

Niemożliwe jest to matematycznie bez pętli. Aby stworzyć odwzorowanie F dyskretnego zbioru wartości na inny dyskretny zbiór wartości, F musi działać na każdym elemencie ze zbioru źródłowego. (Zasadniczo wymagana jest do tego pętla).

Biorąc to pod uwagę:

Dlaczego potrzebujesz nowej listy? Możesz podejść do problemu, który rozwiązujesz w niewłaściwy sposób.

Jeśli masz listę Student, to podczas iteracji tej listy dzieli Cię tylko krok lub dwa od iteracji po numerach identyfikacyjnych uczniów.

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

Jeśli masz inny problem, skomentuj / zaktualizuj pytanie, a postaramy się Ci pomóc.


Na początku dziękuję za odpowiedź. Jednak to dramatyczne, że powiedziałeś, że potrzeba nowej listy jest niewłaściwa. Ponieważ zależy to od pojemności i zakresu potrzeb. Dlatego twoje podejście jest niewłaściwe :) Ponownie moja wzmianka o „możliwości osiągnięcia tego bez pętli” jest o wygodniejszym sposobie, aby kod nie stał się nieczytelny i mało wydajny. W każdym razie, już znalazłem sposób, aby to osiągnąć, trochę się nim podzielę.
— Javatar

Nie powiedziałem, że to zły sposób, ale może to być zły sposób, w zależności od problemu, który próbujesz rozwiązać.
— Zéychin
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.