64

由于 Java 不允许将方法作为参数传递,您使用什么技巧在 Java 中实现类似于列表推导的 Python ?

我有一个字符串列表(ArrayList)。我需要使用一个函数来转换每个元素,以便获得另一个列表。我有几个函数将一个字符串作为输入并返回另一个字符串作为输出。如何制作一个可以将列表和函数作为参数提供的通用方法,以便我可以在处理每个元素时返回一个列表。从字面上看是不可能的,但是我应该使用什么技巧呢?

另一种选择是为每个较小的字符串处理函数编写一个新函数,该函数简单地循环整个列表,这有点不太酷。

4

7 回答 7

78

在 Java 8 中,您可以使用方法引用:

List<String> list = ...;
list.replaceAll(String::toUpperCase);

或者,如果你想创建一个新的列表实例:

List<String> upper = list.stream().map(String::toUpperCase).collect(Collectors.toList());
于 2013-05-24T09:52:55.317 回答
38

基本上,您创建一个 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();
    }
});

或创建一个新的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();
    }
});

哪个更可取取决于您的用例。如果您的列表非常大,就地解决方案可能是唯一可行的解​​决方案;如果您希望将许多不同的功能应用于同一个原始列表以制作许多衍生列表,您将需要该map版本。

于 2009-05-22T18:03:05.003 回答
16

Google Collections 库有很多类用于处理集合和迭代器,它们比普通 Java 支持的级别高得多,并且以功能方式(过滤器、映射、折叠等)。它定义了 Function 和 Predicate 接口以及使用它们来处理集合的方法,因此您不必这样做。它还具有方便的功能,使处理 Java 泛型变得不那么困难。

我还使用Hamcrest ** 来过滤集合。

这两个库很容易与适配器类结合使用。


** 利益声明:我共同撰写了 Hamcrest

于 2009-05-22T18:02:12.570 回答
4

Apache Commons CollectionsUtil.transform(Collection, Transformer) 是另一种选择。

于 2009-05-22T18:54:46.150 回答
1

我正在构建这个项目以用 Java 编写列表理解,现在是https://github.com/farolfo/list-comprehension-in-java中的概念证明

例子

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

如果我们想以某种方式转换输出表达式,例如

// { 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}
于 2015-06-18T18:58:19.817 回答
0

您可以对函数使用 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;
    }
}

用法:

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"]
于 2016-08-23T12:29:58.020 回答
0
import java.util.Arrays;

class Soft{
    public static void main(String[] args){
        int[] nums=range(9, 12);
        System.out.println(Arrays.toString(nums));
    }
    static int[] range(int low, int high){
        int[] a=new int[high-low];
        for(int i=0,j=low;i<high-low;i++,j++){
            a[i]=j;
        }
        return a;

    }
}

希望,我可以帮助你:)

于 2020-06-05T23:59:17.140 回答