Java中类Python的列表理解
由于Java不允许传递方法作为参数,你使用什么技巧来实现像Java中的列表理解一样的Python?
我有一个列表(ArrayList)的string。 我需要通过使用函数来转换每个元素,以便我得到另一个列表。 我有几个函数将一个string作为input,并返回另一个string作为输出。 我如何做一个generics的方法,可以给列表和函数作为参数,以便我可以得到每个处理元素的列表。 在字面意义上是不可能的,但是我应该使用什么技巧?
另一个select是为每个较小的string处理函数编写一个新的函数,它只是在整个列表上循环,这不是很酷。
基本上,你创build一个function界面:
public interface Func<In, Out> { public Out apply(In in); }
然后将一个匿名的子类传递给你的方法。
您的方法可以将该函数应用于每个元素:
public static <T> void applyToListInPlace(List<T> list, Func<T, T> f) { ListIterator<T> itr = list.listIterator(); while (itr.hasNext()) { T output = f.apply(itr.next()); itr.set(output); } } // ... List<String> myList = ...; applyToListInPlace(myList, new Func<String, String>() { public String apply(String in) { return in.toLowerCase(); } });
或创build一个新的List
(基本上创build从input列表到输出列表的映射):
public static <In, Out> List<Out> map(List<In> in, Func<In, Out> f) { List<Out> out = new ArrayList<Out>(in.size()); for (In inObj : in) { out.add(f.apply(inObj)); } return out; } // ... List<String> myList = ...; List<String> lowerCased = map(myList, new Func<String, String>() { public String apply(String in) { return in.toLowerCase(); } });
哪一个更好取决于你的用例。 如果您的清单非常大,就地解决scheme可能是唯一可行的解决scheme; 如果您希望将许多不同的function应用于相同的原始列表以制作多个派生列表,则需要map
版本。
在Java 8中,您可以使用方法引用:
List<String> list = ...; list.replaceAll(String::toUpperCase);
或者,如果你想创build一个新的列表实例:
List<String> upper = list.stream().map(String::toUpperCase).collect(Collectors.toList());
Google Collections库有许多用于处理集合和迭代器的类,它们的级别远高于普通Java支持的级别,并且具有function性(filter,映射,折叠等)的function。 它定义了函数和谓词接口和使用它们来处理集合的方法,所以你不必这样做。 它也有便利的function,使处理Javagenerics不那么艰难。
我也使用Hamcrest **来过滤集合。
这两个库很容易与适配器类相结合。
**感兴趣的声明:我与Hamcrest合着
Apache Commons CollectionsUtil.transform(Collection,Transformer)是另一种select。
我正在构build这个项目来编写Java中的列表理解,现在是https://github.com/farolfo/list-comprehension-in-java中的概念validation
例子
// { x | x E {1,2,3,4} ^ x is even } // gives {2,4} Predicate<Integer> even = x -> x % 2 == 0; List<Integer> evens = new ListComprehension<Integer>() .suchThat(x -> { x.belongsTo(Arrays.asList(1, 2, 3, 4)); x.is(even); }); // evens = {2,4};
如果我们想以某种方式来转换输出expression式
// { x * 2 | x E {1,2,3,4} ^ x is even } // gives {4,8} List<Integer> duplicated = new ListComprehension<Integer>() .giveMeAll((Integer x) -> x * 2) .suchThat(x -> { x.belongsTo(Arrays.asList(1, 2, 3, 4)); x.is(even); }); // duplicated = {4,8}
你可以使用lambdas作为函数,就像这样:
class Comprehension<T> { /** *in: List int *func: Function to do to each entry */ public List<T> comp(List<T> in, Function<T, T> func) { List<T> out = new ArrayList<T>(); for(T o: in) { out.add(func.apply(o)); } return out; } }
用法:
List<String> stuff = new ArrayList<String>(); stuff.add("a"); stuff.add("b"); stuff.add("c"); stuff.add("d"); stuff.add("cheese"); List<String> newStuff = new Comprehension<String>().comp(stuff, (a) -> { //The <String> tells the comprehension to return an ArrayList<String> a.equals("a")? "1": (a.equals("b")? "2": (a.equals("c")? "3": (a.equals("d")? "4": a ))) });
将返回:
["1", "2", "3", "4", "cheese"]