简体   繁体   English

从ArrayList获取元素列表

[英]Getting a list of elements from an ArrayList

Let's say I have a bean like below. 假设我有一个像下面这样的豆子。

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

Then from a method I get a List<Customer> back. 然后从一个方法我得到一个List<Customer> Now let's say I want to get a list of all member "name" from the List. 现在让我们说我想从列表中获取所有成员“名称”的列表。 Obviously I can traverse and build a List<String> of element "name" myself. 显然,我可以自己遍历并构建元素“name”的List<String>

However, I was wondering if there is a short cut or more effiecient way to this technique that anyone knows . 但是,我想知道是否有一种捷径或更有效的方式来解决这种技术。 For instance, if I want to get a list of all keys in a Map object I get do map.keySet(). 例如,如果我想获取Map对象中所有键的列表,我会得到map.keySet()。 Something along that line is what I am trying to find out. 这条线上的东西是我想要找到的东西。

Guava has Lists.transform that can transform a List<F> to a List<T> , using a provided Function<F,T> (or rather, Function<? super F,? extends T> ). Guava有Lists.transform ,它可以使用提供的Function<F,T> (或者更确切地说, Function<? super F,? extends T> )将List<F>转换为List<T>

From the documentation: 从文档:

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

Returns a list that applies function to each element of fromList . 返回一个列表,该functionfunction应用于fromList每个元素。 The returned list is a transformed view of fromList ; 返回的列表是fromList的转换视图; changes to fromList will be reflected in the returned list and vice versa. fromList更改将反映在返回的列表中,反之亦然。

The function is applied lazily, invoked when needed. function被懒惰地应用,在需要时调用。

Similar live-view transforms are also provided as follows: 类似的实时视图转换也提供如下:

Looks like you're looking for the Java equivalent of Perl's map function. 看起来你正在寻找与Perl的map函数相当的Java。 This kind of thing might be added to the collections library once (if) Java receives closures. 这种事情可能会被添加到集合库中一次(如果)Java接收闭包。 Until then, I think this is the best you can do: 在那之前,我认为这是你能做的最好的事情:

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

You could also write a map function that uses a simple interface to provide the mapping function. 你也可以写一个map ,它使用一个简单的界面提供映射函数功能。 Something like this: 像这样的东西:

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;
}

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

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

You can use LambdaJ 's Converter interface and have the following line: 您可以使用LambdaJConverter接口,并具有以下行:

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

You need to use a loop, but the function you're looking for is called map in functional languages. 您需要使用循环,但您正在寻找的函数在函数式语言中称为map It's possible to implement map in Java, although it tends to be fairly inelegant; 可以用Java实现map ,虽然它往往相当不优雅; here's the version I implemented ages ago in my "stuff Java should have but for some reason doesn't" library: 这是我很久以前在我的“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;
}

Using that, you could do: 使用它,你可以这样做:

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();
    }
}));

You could naturally change map to take collections instead of arrays, which would eliminate the need for Arrays.asList and List.toArray 你可以自然地改变map来获取集合而不是数组,这将消除对Arrays.asListList.toArray的需求。

Using Guava , you can use a Function along with Iterables.transform , Collections2.transform or Lists.transform to create an Iterable , Collection or List respectively. 使用Guava ,您可以使用函数以及Iterables.transformCollections2.transformLists.transform分别创建IterableCollectionList

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

The returned Iterable is lazy and applies the function to the underlying list as you iterate through it. 返回的Iterable是惰性的,并在迭代它时将函数应用于基础列表。 For a List<String> containing the names, you could use: 对于包含名称的List<String> ,您可以使用:

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

or 要么

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

Of course, writing out the anonymous inner class Function implementation each time you want to do this is ugly and verbose, so you may want to make the Function a constant available from the Customer class, called Customer.NAME for instance. 当然,写出匿名内部类Function你想做的事,这是丑陋的和详细的每一次实施,所以你可能想使Function恒定可从Customer类,名为Customer.NAME的实例。

Then the transformation looks much nicer (with static imports especially): 然后转换看起来更好(尤其是静态导入):

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

I also wrote about using interfaces for particular properties of objects (such as name here) to help with consolidating such functions on my blog here . 我也写了一篇关于使用接口为对象的特定属性(如name这里)来帮助我的博客上巩固这样的功能在这里

.... is there a short cut or more efficient way ....是否有捷径或更有效的方式

So, are you looking for a more efficient way to do this: 那么,您是否正在寻找一种更有效的方法来执行此操作:

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

?!!!! ?!!!!

Or just a different way? 或者只是一种不同的方式?

All the previous answer are not really more efficient in terms of runtime nor coding. 之前的所有答案在运行时和编码方面都没有那么高效。 They are however more flexible without a doubt. 然而,毫无疑问,它们更具弹性。

Another alternative would be to include Scala Groovy in your Java code and use this: 另一种方法是在Java代码中包含 Scala Groovy并使用它:

list.map( _.name )

list.collect { it.name }

If compiled, Groovy classes may be used from Java, or you can plug in them as an script. 如果编译,可以从Java使用Groovy类,或者您可以将它们作为脚本插入。

Here's a sample for the given Customer class using Groovy as script. 这是使用Groovy作为脚本的给定Customer类的示例。

    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);

Output: 输出:

names = [A, B, C, D]

note: I extracted method for readability, but you can see them below 注意:我提取了方法以便于阅读,但您可以在下面看到它们

But, again that's just different, not really more efficient than the regular for loop. 但是,这又是不同的,并不比常规for循环更有效。

Here's the complete source code . 这是完整的源代码 To run it you just need Java1.6 and Groovy in the classpath. 要运行它,您只需要在类路径中使用Java1.6和Groovy。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM