Як створити новий список із властивістю об’єкта, який знаходиться в іншому списку


81

Уявіть, що у мене є список певних об’єктів:

List<Student>

І мені потрібно сформувати ще один список, включаючи idsз Studentsнаведеного у списку:

List<Integer>

Уникаючи використання циклу, чи можливо це досягти за допомогою колекцій apache або гуави ?

Які методи повинні бути корисними для мого випадку?


Гей, я знайшов тільки зараз: stackoverflow.com/questions/737244 / ...
Javatar

Відповідь Джона досить класна, але якщо поглянути на неї, вона також використовує цикл. Будь-яке будь-яке рішення буде використовувати цикл - хоча він може бути не видимим для вас, але внутрішньо він буде
hage

хтось повинен застосувати цикл, щоб це зробити. або ви, або якась бібліотека, яку ви можете використовувати
Судмонг

Насправді відповідь Джона не відповідає моїй ситуації, оскільки я не хочу використовувати цикл. Я думаю, що є кудись зручніший спосіб, але чекай, поки я його знайду :)
Javatar

Відповіді:


175

Спосіб Java 8: -

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

2
Що робити, якщо я хочу список кортежів? Щось на зразок [(Id, name), (Id, name)].
Coder95,

Не всі функції 1.8 підтримуються для всіх API Android. Зокрема, java.util.stream не підтримується до API 24.
The Black Horse

41

За допомогою Guava ви можете використовувати таку функцію, як -

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

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

і ви можете використовувати цю функцію для перетворення списку студентів на ідентифікатори типу -

Lists.transform(studentList, StudentToId.INSTANCE);

Звичайно, він буде циклічно витягувати всі ідентифікатори, але пам'ятайте, що методи guava повертають подання, і функція застосовуватиметься лише тоді, коли ви намагаєтеся виконати ітерацію, List<Integer>
якщо ви не повторите ітерацію, вона ніколи не застосує цикл.

Примітка. Пам'ятайте, що це вигляд, і якщо ви хочете повторити кілька разів, буде краще скопіювати вміст в інший, List<Integer>наприклад

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

Я думаю, що неелегантно визначати функцію окремо. Я думаю , що це може бути зроблено анонімно і в один крок процесу
Marc

як витягувати рядкові (плаваючі тощо) члени Списку?
sepehr

22

Завдяки Премраю за альтернативний крутий варіант, проголосований.

Я використовував apache CollectionUtils та BeanUtils. Відповідно, я задоволений роботою наступного коду:

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

Варто зазначити, що я порівняю продуктивність гуави ( надається Premraj ) та collectionUtils, я використовував вище, і вирішу швидший.


3
Я віддаю перевагу гуаві перед колекціями apache, незалежно від продуктивності, з таких причин, як - більш сучасний, загальний, не використовує відображення для перетворень і т. Д. Загалом гуава набагато сучасніша за колекції apache - читайте більше тут
Премрай

1
Так, але насправді мені не здається гарною ідеєю обмежувати його використання шляхом обов’язкової необхідності додаткової декларації переліку для кожного типу об’єкта, який я хочу перетворити.
Javatar

Ну, це залежить від вашого дизайну - ви можете запропонувати інтерфейс, Identifiableякий визначає getId()метод, а потім ви можете використовувати цей єдиний шаблон перерахування для загального вилучення ідентифікатора.
Премрай

2
гуава, безумовно, є більш ефективною, ніж утиліти Bean, оскільки пізніше використовуються роздуми ..
Раві

2
Використання імені властивості як рядка в конструкторі new BeanToPropertyValueTransformer ("id") - це те, чого я точно намагаюся уникати. Рефакторинг буде важким! Але я шукаю рішення для вирішення цього питання. Тим часом я прийду рішення Гуави, багатослівне, але безпечне.
redochka

7

Рішення лямбда-виразу Java 8:

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

Якщо Java <1.8, то використовуйте Apache CollectionUtils. Приклад: Колекція <String> firstnames = CollectionUtils.collect (список користувачів, TransformerUtils.invokerTransformer ("getFirstname"));
a_subscriber

5

Якщо хтось потрапить сюди через кілька років:

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

І ти мене щойно врятував :)
Behrad3d,

-5

З математичної точки зору це неможливо зробити без циклу. Для того, щоб створити відображення, F, дискретного набору значень в інший дискретний набір значень, F повинен оперувати кожним елементом у вихідному наборі. (В основному для цього потрібен цикл.)

Це сумно:

Навіщо потрібен новий список? Ви можете підійти до будь-якої проблеми, яку вирішуєте, неправильно.

Якщо у вас є список Student, то вам потрібно лише крок-два, коли ви перебираєте цей список, від перебору ідентифікаційних номерів студентів.

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

Якщо у вас інша проблема, то коментуйте / оновлюйте питання, і ми спробуємо вам допомогти.


Спочатку дякую за вашу відповідь. Однак драматично, що ви сказали, що потрібен новий список - неправильний шлях. Тому що це залежить від потужності та діапазону потреби. Тому ваш підхід неправильний: :) Знову ж моя згадка про "здатність досягати цього без циклу" - про більш зручний спосіб, щоб не робити код нечитабельним і низькопродуктивним. У будь-якому випадку, я вже знайшов спосіб досягти цього, збираючись трохи поділитися.
Javatar

Я не говорив , що це неправильний шлях, але це може бути неправильно, в залежності від проблеми , яку ви намагаєтеся вирішити.
Zéychin
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.