代码之家  ›  专栏  ›  技术社区  ›  euphoria83

Java中的Python类列表理解

  •  53
  • euphoria83  · 技术社区  · 15 年前

    既然Java不允许传递方法作为参数,那么在Java中,你用什么技巧来实现Python类列表理解呢?

    我有一个字符串列表。我需要使用一个函数来转换每个元素,以便得到另一个列表。我有几个函数将一个字符串作为输入并返回另一个字符串作为输出。如何生成一个通用方法,它可以被赋予列表和作为参数的函数,这样我就可以在处理每个元素后得到一个列表。从字面意义上讲是不可能的,但是我应该使用什么技巧呢?

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

    6 回复  |  直到 8 年前
        1
  •  35
  •   Michael Myers KitsuneYMG    15 年前

    基本上,创建一个函数接口:

    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 版本。

        2
  •  43
  •   yurez    9 年前

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

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

    或者,如果要创建新的列表实例:

    List<String> upper = list.stream().map(String::toUpperCase).collect(Collectors.toList());
    
        3
  •  17
  •   Nat    15 年前

    这个 Google Collections library 有很多类用来处理集合和迭代器,它们比普通Java支持要高得多,并且以功能性的方式(过滤器、映射、折叠等)。它定义了函数和谓词接口以及使用它们来处理集合的方法,这样您就不必这样做。它还具有方便处理Java泛型的功能。

    我也用 Hamcrest **用于筛选集合。

    这两个库很容易与适配器类组合在一起。


    **利益声明:我共同撰写了《汉克雷斯特》。

        4
  •  5
  •   Michael Myers KitsuneYMG    15 年前

    阿帕奇公地 CollectionsUtil.transform(Collection, Transformer) 是另一个选择。

        5
  •  1
  •   farolfo    9 年前

    我正在构建这个项目来用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}
    
        6
  •  0
  •   MrYurihi redstone    8 年前

    您可以使用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"]