Java 中类似 Python 的列表理解
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/899138/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Python-like list comprehension in Java
提问by euphoria83
Since Java doesn't allow passing methods as parameters, what trick do you use to implement Python like list comprehension in Java ?
由于 Java 不允许将方法作为参数传递,那么在 Java 中您使用什么技巧来实现 Python 之类的列表理解?
I have a list (ArrayList) of Strings. I need to transform each element by using a function so that I get another list. I have several functions which take a String as input and return another String as output. How do I make a generic method which can be given the list and the function as parameters so that I can get a list back with each element processed. It is not possible in the literal sense, but what trick should I use ?
我有一个字符串列表(ArrayList)。我需要使用函数来转换每个元素,以便获得另一个列表。我有几个函数将一个字符串作为输入并返回另一个字符串作为输出。我如何创建一个通用方法,该方法可以将列表和函数作为参数,以便我可以获取处理每个元素的列表。从字面上看这是不可能的,但是我应该使用什么技巧?
The other option is to write a new function for each smaller String-processing function which simply loops over the entire list, which is kinda not so cool.
另一种选择是为每个较小的字符串处理函数编写一个新函数,它只是循环遍历整个列表,这有点不太酷。
采纳答案by Michael Myers
Basically, you create a Function interface:
基本上,您创建一个 Function 接口:
public interface Func<In, Out> {
public Out apply(In in);
}
and then pass in an anonymous subclass to your method.
然后将匿名子类传递给您的方法。
Your method could either apply the function to each element in-place:
您的方法可以将函数应用到每个元素就地:
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();
}
});
or create a new List
(basically creating a mapping from the input list to the output list):
或创建一个新的List
(基本上是创建从输入列表到输出列表的映射):
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();
}
});
Which one is preferable depends on your use case. If your list is extremely large, the in-place solution may be the only viable one; if you wish to apply many different functions to the same original list to make many derivative lists, you will want the map
version.
哪一个更可取取决于您的用例。如果您的列表非常大,就地解决方案可能是唯一可行的解决方案;如果您希望将许多不同的函数应用于同一个原始列表以制作许多衍生列表,您将需要map
版本。
回答by Nat
The Google Collections libraryhas lots of classes for working with collections and iterators at a much higher level than plain Java supports, and in a functional manner (filter, map, fold, etc.). It defines Function and Predicate interfaces and methods that use them to process collections so that you don't have to. It also has convenience functions that make dealing with Java generics less arduous.
的谷歌集合库拥有大量的类在比普通Java支持高得多的电平与集合和迭代工作,并以功能性方式(过滤器,地图,折叠,等等)。它定义了 Function 和 Predicate 接口以及使用它们来处理集合的方法,这样您就不必这样做了。它还具有方便的功能,使处理 Java 泛型变得不那么困难。
I also use Hamcrest** for filtering collections.
我还使用Hamcrest** 过滤集合。
The two libraries are easy to combine with adapter classes.
这两个库很容易与适配器类结合。
** Declaration of interest: I co-wrote Hamcrest
** 利益声明:我共同编写了 Hamcrest
回答by Michael Myers
Apache Commons CollectionsUtil.transform(Collection, Transformer)is another option.
Apache Commons CollectionsUtil.transform(Collection, Transformer)是另一种选择。
回答by yurez
In Java 8 you can use method references:
在 Java 8 中,您可以使用方法引用:
List<String> list = ...;
list.replaceAll(String::toUpperCase);
Or, if you want to create a new list instance:
或者,如果您想创建一个新的列表实例:
List<String> upper = list.stream().map(String::toUpperCase).collect(Collectors.toList());
回答by farolfo
I'm building this project to write list comprehension in Java, now is a proof of concept in https://github.com/farolfo/list-comprehension-in-java
我正在构建这个项目来用 Java 编写列表理解,现在是https://github.com/farolfo/list-comprehension-in-java 中的概念证明
Examples
例子
// { 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};
And if we want to transform the output expression in some way like
如果我们想以某种方式转换输出表达式,例如
// { 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}
回答by farolfo
You can use lambdas for the function, like so:
您可以对函数使用 lambda,如下所示:
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;
}
}
the usage:
用法:
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
)))
});
will return:
将返回:
["1", "2", "3", "4", "cheese"]