如何使用另一个列表中的对象的属性创建一个新列表

Posted

技术标签:

【中文标题】如何使用另一个列表中的对象的属性创建一个新列表【英文标题】:How to make a new list with a property of an object which is in another list 【发布时间】:2012-06-14 02:39:24 【问题描述】:

假设我有一个特定对象的列表:

List<Student>

我需要生成另一个列表,包括上面列表中Studentsids

List<Integer>

避免使用循环,是否可以通过使用 apache 集合guava 来实现?

哪些方法对我的情况有用?

【问题讨论】:

嘿,我刚刚找到了:***.com/questions/737244/… 乔恩的回答很酷,但如果你看一下,它也使用了循环。任何解决方案都将使用循环 - 尽管您可能看不到它,但在内部它会 必须有人应用循环才能完成。您或您可能使用的某个库。 实际上 jon 的回答不适合我的情况,因为我不想使用 for 循环。我认为在某个地方有更方便的方法,但等我找到它:) 【参考方案1】:

Java 8 的实现方式:-

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

【讨论】:

如果我想要一个元组列表怎么办?类似于 [(Id, name),(Id, name)]。 并非所有 android API 都支持所有 1.8 功能。特别是,直到 API 24 才支持 java.util.stream。【参考方案2】:

有了 Guava,你可以使用 Function like -

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

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

您可以使用此功能将学生列表转换为 id,例如 -

Lists.transform(studentList, StudentToId.INSTANCE);

它肯定会循环以提取所有 id,但请记住 guava 方法返回视图和 Function 只会在您尝试迭代 List&lt;Integer&gt; 时应用 如果您不迭代,它将永远不会应用循环。 注意:请记住这是视图,如果您想多次迭代,最好将内容复制到其他 List&lt;Integer&gt; 之类的地方

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

【讨论】:

我认为必须单独定义一个函数是不优雅的。我认为这也可以匿名完成,一步完成 如何提取 List 的字符串(float 等)成员?【参考方案3】:

感谢 Premraj 提供了另一种很酷的选项,点赞。

我使用过 apache CollectionUtils 和 BeanUtils。因此,我对以下代码的性能感到满意:

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

值得一提的是,我会比较我上面使用的guava(Premraj提供)和collectionUtils的性能,决定哪个更快。

【讨论】:

无论性能如何,我都会更喜欢 Guava 而不是 apache 集合,原因如下 - 更现代、泛型、不使用反射进行转换等。总体而言,guava 比 apache 集合更现代 - 阅读更多 @987654321 @ 是的,但实际上对我来说,通过对我要转换的每种类型的对象强制需要额外的枚举声明来限制它的使用似乎并不是一个好主意。 这取决于你的设计——你可以有接口说Identifiable,它定义了getId()方法,然后你可以使用这个单一的枚举单例模式来提取ID。 guava 肯定比 Bean utils 更高效,因为后者使用反射.. 在构造函数 new BeanToPropertyValueTransformer("id") 中使用属性名称作为字符串是我绝对要避免的。重构会很困难!但我正在寻找解决此问题的解决方案。同时,我将使用 Guava 解决方案,详细但安全。【参考方案4】:

Java 8 lambda 表达式解决方案:

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

【讨论】:

如果 Java firstnames = CollectionUtils.collect(userlist, TransformerUtils.invokerTransformer("getFirstname"));【参考方案5】:

如果有人在几年后来到这里:

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

【讨论】:

你刚刚救了我:)【参考方案6】:

您可以为此目的使用Eclipse Collections

Student first = new Student(1);
Student second = new Student(2);
Student third = new Student(3);

MutableList<Student> list = Lists.mutable.of(first, second, third);
List<Integer> result = list.collect(Student::getId);

System.out.println(result); // [1, 2, 3]

【讨论】:

【参考方案7】:

如果没有循环,在数学上是不可能做到这一点的。为了创建一个离散值集到另一个离散值集的映射 F,F 必须对原始集中的每个元素进行操作。 (基本上,需要一个循环来执行此操作。)

话虽如此:

为什么需要新列表?你可能会以错误的方式解决你正在解决的任何问题。

如果您有一个Student 列表,那么在遍历此列表时,您距离遍历 I.D. 仅一步或两步。学生人数。

for(Student s : list)

    int current_id = s.getID();
    // Do something with current_id

如果您有其他类型的问题,请评论/更新问题,我们会尽力帮助您。

【讨论】:

首先感谢您的回复。但是,您说需要一个新列表是错误的方式,这很戏剧化。因为它取决于需要的容量和范围。因此,您的方法是错误的方法:) 我再次提到“无需循环即可实现该目标的能力”是一种更方便的方法,以免使代码不可读和性能低下。无论如何,我已经找到了实现它的方法,将分享一下。 我没有说它错误的方式,但它可能是错误的方式,这取决于您要解决的问题.

以上是关于如何使用另一个列表中的对象的属性创建一个新列表的主要内容,如果未能解决你的问题,请参考以下文章

如何将列表的子集添加到另一个列表中的对象的属性-最佳/最快的做法

将新属性添加到另一个数组中的现有对象数组

如何在Dart中合并列表

如何在Python中的for循环内创建对象列表而不继承属性值[重复]

如何使用linq / lambda计算具有唯一属性的列表中的对象数?

如何从另一个类访问列表的长度