web-dev-qa-db-ja.com

JavaのPythonのようなリスト内包表記

Javaではメソッドをパラメーターとして渡すことができないため、Pythonのリスト内包表記のようなJavaを実装するためにどのようなトリックを使用しますか?

文字列のリスト(ArrayList)があります。関数を使用して各要素を変換し、別のリストを取得する必要があります。入力として文字列を取り、出力として別の文字列を返す関数がいくつかあります。リストと関数をパラメーターとして指定できる汎用メソッドを作成して、各要素が処理されたリストを取得するにはどうすればよいですか?文字通りの意味では不可能ですが、どのようなトリックを使用する必要がありますか?

もう1つのオプションは、リスト全体を単純にループする小さな文字列処理関数ごとに新しい関数を作成することです。これは、それほどクールではありません。

52
euphoria83

基本的に、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バージョンが必要になります。

35
Michael Myers

Java 8では、メソッド参照を使用できます。

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

または、新しいリストインスタンスを作成する場合:

List<String> upper = list.stream().map(String::toUpperCase).collect(Collectors.toList());
47
yurez

Googleコレクションライブラリ には、プレーンJavaがサポートするよりもはるかに高いレベルで、機能的な方法(フィルター、マップ、折り畳みなど)でコレクションとイテレーターを操作するための多くのクラスがあります。)。これは、コレクションを処理するために使用する必要がないように、FunctionおよびPredicateインターフェースとメソッドを定義します。また、Javaジェネリックを扱いにくくする便利な関数もあります。

コレクションのフィルタリングには Hamcrest **も使用します。

2つのライブラリは、アダプタクラスと簡単に組み合わせることができます。


**関心の宣言:Hamcrestを共同で書きました

17
Nat

Apache Commons CollectionsUtil.transform(Collection、Transformer) は別のオプションです。

5
user111246

私はこのプロジェクトを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}
1
farolfo

次のように、関数にラムダを使用できます。

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"]
0