从 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.transform
(Iterable<F>
到 Iterable<T>
)
Iterators.transform
(Iterator<F>
到 Iterator<T>
)
Collections2.transform
(Collection<F>
到 Collection<T>
)
Maps.transformValues
(Map<K,V1>
到 Map<K,V2>
)
【讨论】:
酷,很高兴看到一个库的链接,该库基本上符合我在帖子中的建议。 @Mark:最大的不同在于 Guava 的实现是按需应用函数。有点“懒惰的变换”,正如你所渴望的那样。 啊,我很好奇他们为什么专门使用可迭代。这就解释了原因。我现在更喜欢它了(假设 Guava 中有一个工厂方法可以从可迭代对象中创建一个集合?) @Mark:我环顾四周,发现Collections2.transform
。但是,是的,从 Iterable
到 Collection
有 Iterables.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.asList
和 List.toArray
的需要
【讨论】:
【参考方案7】:使用Guava,您可以使用Function 和Iterables.transform、Collections2.transform 或Lists.transform 分别创建Iterable
、Collection
或List
。
Iterable<String> names = Iterables.transform(customers,
new Function<Customer, String>()
public String apply(Customer from)
return from.getName();
);
返回的Iterable
是惰性的,并在您遍历它时将函数应用于底层列表。对于包含名称的List<String>
,您可以使用:
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 中获取元素列表的主要内容,如果未能解决你的问题,请参考以下文章
如何使用适配器为recyclerview从字符串数组列表中的元素获取字符串