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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 20:49:05  来源:igfitidea点击:

Python-like list comprehension in Java

javapythonparametersmethodslist-comprehension

提问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 mapversion.

哪一个更可取取决于您的用例。如果您的列表非常大,就地解决方案可能是唯一可行的解​​决方案;如果您希望将许多不同的函数应用于同一个原始列表以制作许多衍生列表,您将需要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"]