从 ArrayList 中获取元素列表

Posted

技术标签:

【中文标题】从 ArrayList 中获取元素列表【英文标题】:Getting a list of elements from an ArrayList 【发布时间】:2010-06-24 17:37:01 【问题描述】:

假设我有一个如下所示的 bean。

class Customer
  private String code;
  private String name;
  private Integer value;
  //getters setters omitted for brevity

然后从一个方法我得到一个List<Customer> 回来。现在假设我想从列表中获取所有成员“名称”的列表。显然,我可以自己遍历并构建元素“名称”的List<String>

但是,我想知道是否有任何人都知道的这种技术的捷径或更有效的方法。例如,如果我想获取 Map 对象中所有键的列表,我可以使用 map.keySet()。沿着这条线的东西是我试图找出的。

【问题讨论】:

我认为你被卡住了,或者如果你喜欢冒险,你可以看看quaere。查看What is the Java equivalent for LINQ? 了解一些相关信息。 我认为您不是在寻找更有效的方式,而是在寻找更有效的方式。默认的 for 循环已经足够高效了。 嗯,不一定是效率方面的,但我试图了解其他人为像这样的日常任务做了什么。我了解到 Guava 和 Lambdaj 是一些流行的替代品。所以这很好! 【参考方案1】:

Guava 有Lists.transform,可以使用提供的Function<F,T>(或者更确切地说,Function<? super F,? extends T>)将List<F> 转换为List<T>

来自文档:

public static <F,T>
   List<T> transform(
               List<F> fromList,
               Function<? super F,? extends T> function
           )

返回将function 应用于fromList 的每个元素的列表。返回的列表是fromList 的转换视图;对fromList 的更改将反映在返回的列表中,反之亦然。

function 被延迟应用,在需要时调用。

还提供了类似的实时视图转换,如下所示:

Iterables.transformIterable&lt;F&gt;Iterable&lt;T&gt;Iterators.transformIterator&lt;F&gt;Iterator&lt;T&gt;Collections2.transformCollection&lt;F&gt;Collection&lt;T&gt;Maps.transformValuesMap&lt;K,V1&gt;Map&lt;K,V2&gt;

【讨论】:

酷,很高兴看到一个库的链接,该库基本上符合我在帖子中的建议。 @Mark:最大的不同在于 Guava 的实现是按需应用函数。有点“懒惰的变换”,正如你所渴望的那样。 啊,我很好奇他们为什么专门使用可迭代。这就解释了原因。我现在更喜欢它了(假设 Guava 中有一个工厂方法可以从可迭代对象中创建一个集合?) @Mark:我环顾四周,发现Collections2.transform。但是,是的,从 IterableCollectionIterables.addAll @Mark Peters 是的,Guava 可以从 Iterable 中创建任何类型的 Collection,使用 Lists 之类的工厂方法或所有不可变集合上的 copyOf(Iterable) 工厂方法类。【参考方案2】:

看起来您正在寻找 Perl 的 map 函数的 Java 等效项。一旦(如果)Java 接收到闭包,这种东西可能会被添加到集合库中。在那之前,我认为这是你能做的最好的:

List<String> list = new ArrayList<String>(customers.size());
for ( Customer c : customers ) 
    list.add(c.getName());

您还可以编写一个map 函数,它使用一个简单的接口来提供映射函数。像这样的:

public interface Transform<I, O> 
    O transform(I in);

public <I, O> List<O> map(Collection<I> coll, Transform<? super I, ? extends O> xfrm) 
    List<O> list = new ArrayList<O>(coll.size());
    for ( I in : coll ) 
        list.add(xfrm.transform(in));
    
    return list;

【讨论】:

“Perl 的”映射函数?呵呵!你不是说Java相当于Perl相当于Lisp的map函数吗?【参考方案3】:

可以使用这样的东西: http://code.google.com/p/lambdaj/

【讨论】:

【参考方案4】:

我认为这是你必须自己编写代码的东西,在一个循环中。

【讨论】:

使用 LambdaJ 你只需要编写转换器 Customer->String 或者更好 ;-) guava 的 Lists.transform guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/…, com.google.common.base.Function)【参考方案5】:

你可以使用LambdaJ的Converter接口,有如下一行:

List<String> customerNames = convert(customerList, new Converter<Customer,String>() 
  public String convert(Customer customer) 
    return customer.getName();
  
);

【讨论】:

有趣。你知道它是否适用于 jdk 1.5 还是仅适用于 Java 6?【参考方案6】:

您需要使用循环,但您要查找的函数在函数式语言中称为map。在 Java 中实现map 是可能的,尽管它往往相当不优雅;这是我多年前在“Java 应该有但由于某种原因没有”库中实现的版本:

public interface MapFunction<T, U> 
    public U map(T source);


public static <T, U> U[] map(T[] objects, MapFunction<T, U> f) 
    if(objects.length == 0) throw new IllegalArgumentException("Can't map onto an empty array");
    @SuppressWarnings("unchecked") U[] rtn = (U[])Array.newInstance(f.map(objects[0]).getClass(), objects.length);
    for(int i = 0; i < objects.length; i++)
        rtn[i] = f.map(objects[i]);
    return rtn;

使用它,你可以这样做:

List<Customer> list = yourFunction();
List<String> names = Arrays.asList(map(list.toArray(new Customer[0]), new MapFunction<Customer, String>() 
    public String map(Customer c) 
        return c.getName();
    
));

您可以自然地更改 map 以获取集合而不是数组,这将消除对 Arrays.asListList.toArray 的需要

【讨论】:

【参考方案7】:

使用Guava,您可以使用Function 和Iterables.transform、Collections2.transform 或Lists.transform 分别创建IterableCollectionList

Iterable<String> names = Iterables.transform(customers, 
    new Function<Customer, String>() 
      public String apply(Customer from) 
        return from.getName();
      
    );

返回的Iterable 是惰性的,并在您遍历它时将函数应用于底层列表。对于包含名称的List&lt;String&gt;,您可以使用:

List<String> names = Lists.transform(...);

ImmutableList<String> names = ImmutableList.copyOf(Iterables.transform(...));

当然,每次你想写出匿名内部类 Function 实现是丑陋和冗长的,所以你可能想让 Function 成为 Customer 类中可用的常量,称为 @比如987654338@。

然后转换看起来更好(尤其是静态导入):

for (String name : transform(customers, Customer.NAME))  ... 

我还在我的博客here 上写了关于使用对象特定属性的接口(例如name 此处)来帮助整合这些功能。

【讨论】:

好吧,你和多基因都给出了类似的答案。如果我能接受两个正确的答案,那么我也会接受你的。谢谢!【参考方案8】:

....有没有捷径或更有效的方法

那么,您是否正在寻找一种更有效的方法来做到这一点:

 List<String> names = new ArrayList<String>();
 for( Customer customer : yourCustomerList ) 
     names.add( customer.getName() );
 

?!!!!

或者只是一种不同的方式?

所有先前的答案在运行时和编码方面都不是真的更有效。然而,毫无疑问,它们更灵活。

另一种选择是在您的 Java 代码中包含 Scala Groovy 并使用它:

list.map( _.name )

list.collect  it.name 

如果已编译,则可以从 Java 中使用 Groovy 类,或者您可以将它们作为脚本插入。

这里是给定Customer 类的示例,它使用Groovy 作为脚本。

    List<Customer> customers = Arrays.asList( new Customer[]
       new Customer("A","123",1),
       new Customer("B","456",2),
       new Customer("C","789",3),
       new Customer("D","012",4)
    );

    setVariable(customers, "list");
    evaluate("names = list.collect  it.name  ");
    List<String> names = (List<String>) getVariable("names");
    System.out.println("names = " + names);

输出:

names = [A, B, C, D]

注意:我提取方法是为了便于阅读,但您可以在下面看到它们

但是,这又是不同的,并不比常规的 for 循环更有效。

这是complete source code。要运行它,您只需要类路径中的 Java1.6 和 Groovy。

【讨论】:

谢谢,我听说过 Groovy,但还没有搞砸。这看起来很整洁。

以上是关于从 ArrayList 中获取元素列表的主要内容,如果未能解决你的问题,请参考以下文章

获取最后添加的元素 Arraylist

如何使用适配器为recyclerview从字符串数组列表中的元素获取字符串

如何获取大于数组列表中当前元素的数字元素的计数[关闭]

从arraylist中获取不重复的项目[关闭]

如何从 ArrayList<HashMap<String, String>> android 中获取所有元素

有效地从 ArrayList 中获取子列表