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


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.