Получение списка элементов из ArrayList
предположим, у меня есть боб, как показано ниже.
class Customer{
private String code;
private String name;
private Integer value;
//getters setters omitted for brevity
}
тогда из метода я получаю List<Customer>
обратно. Теперь предположим, что я хочу получить список всех членов "name" из списка. Очевидно, я могу пересечь и построить List<String>
элемента "имя" себе.
однако мне было интересно, есть ли короткий путь или более эффективный способ этой техники, который кто-нибудь знает . Например,если я хочу получить список всех ключей в объекте карты, я получаю карту do.набор ключей.)( Что-то в этом роде. линия-это то, что я пытаюсь выяснить.
8 ответов
гуава имеет Lists.transform
это может преобразовать List<F>
до List<T>
, используя предоставленный Function<F,T>
(вернее, Function<? super F,? extends T>
).
из документации:
public static <F,T> List<T> transform( List<F> fromList, Function<? super F,? extends T> function )
возвращает список, который применяется
function
в каждом элементеfromList
. Возвращаемый список представляет собой преобразованное представлениеfromList
иfromList
будет отражено в возвращенном списке и наоборот.на
function
применяется лениво, вызывается при необходимости.
аналогичные преобразования live-view также предоставляются следующим образом:
-
Iterables.transform
(Iterable<F>
toIterable<T>
) -
Iterators.transform
(Iterator<F>
toIterator<T>
) -
Collections2.transform
(Collection<F>
toCollection<T>
) -
Maps.transformValues
(Map<K,V1>
toMap<K,V2>
)
Похоже, вы ищете Java-эквивалент Perl 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;
}
могли бы использовать что-то вроде этого: http://code.google.com/p/lambdaj/
вам нужно использовать цикл, но функция которую вы ищете называется map
в функциональных языках. Возможно реализовать map
в Java, хотя это, как правило, довольно неэлегантно; вот версия, которую я реализовал много лет назад в моем "материале 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();
}
}));
вы можете естественным образом изменить карту, чтобы взять коллекции вместо массивов, что устранит необходимость Arrays.asList
и List.toArray
используя гуавы, вы можете использовать функции вместе с Iterables.transform, Collections2.transform или списки.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
класс, называемый Customer.NAME
например.
тогда преобразование выглядит намного лучше (особенно со статическим импортом):
for (String name : transform(customers, Customer.NAME)) { ... }
я также писал об использовании интерфейсов для определенных свойств объекты (например,name
здесь), чтобы помочь с консолидацией таких функций в моем блоге здесь.
.... есть ли короткий путь или более эффективный способ
Итак, вы ищете более эффективный способ сделать это:
List<String> names = new ArrayList<String>();
for( Customer customer : yourCustomerList ) {
names.add( customer.getName() );
}
?!!!!
или просто разные путь?
все предыдущие ответы на самом деле не более эффективны с точки зрения времени выполнения или кодирования. Однако они, без сомнения, более гибкие.
Другой альтернативой было бы включить Scala Groovy в вашем коде Java и используйте это:
list.map( _.name )
list.collect { it.name }
если скомпилированы, Groovy классы могут быть использованы из Java, или вы можете подключить их в качестве сценария.
вот образец для данного 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.
здесь исходный код. Чтобы запустить его, вам просто нужен Java1.6 и заводной в classpath.