25

関数を Java コレクション (この場合はマップ) に適用したいと考えています。これを行う良い方法はありますか?マップがあり、マップ内のすべての値に対して trim() を実行し、マップに更新を反映させたいと考えています。

4

8 に答える 8

38

Java 8 のラムダでは、これは 1 つのライナーです。

map.replaceAll((k, v) -> v.trim());

歴史のために、ラムダなしのバージョンを次に示します。

public void trimValues(Map<?, String> map) {
  for (Map.Entry<?, String> e : map.entrySet()) {
    String val = e.getValue();
    if (val != null)
      e.setValue(val.trim());
  }
}

または、より一般的に:

interface Function<T> {
  T operate(T val);
}

public static <T> void replaceValues(Map<?, T> map, Function<T> f)
{
  for (Map.Entry<?, T> e : map.entrySet())
    e.setValue(f.operate(e.getValue()));
}

Util.replaceValues(myMap, new Function<String>() {
  public String operate(String val)
  {
    return (val == null) ? null : val.trim();
  }
});
于 2009-04-13T16:31:50.457 に答える
11

受け入れられた応答以外のJDKライブラリでそれを行う方法はわかりませんが、Googleコレクションでは、クラスcom.google.collect.Mapsとを使用して次のことができcom.google.common.base.Functionます。

Map<?,String> trimmedMap = Maps.transformValues(untrimmedMap, new Function<String, String>() {
  public String apply(String from) {
    if (from != null)
      return from.trim();
    return null;
  }
}

その方法と提案された方法との最大の違いは、元のマップへのビューを提供することです。つまり、元のマップと常に同期していますが、そのapplyマップを頻繁に操作している場合、メソッドが何度も呼び出される可能性があります。 .

コレクションにも同様のCollections2.transform(Collection<F>,Function<F,T>)方法があります。

于 2009-09-15T09:08:20.200 に答える
2

このようなものにはやり過ぎかもしれませんが、Apache Commons Collectionsライブラリには、この種の問題に対応する非常に優れたユーティリティが多数あります。

Map<String, String> map = new HashMap<String, String>(); 
map.put("key1", "a  ");
map.put("key2", " b ");
map.put("key3", "  c");

TransformedMap.decorateTransform(map, 
  TransformerUtils.nopTransformer(), 
  TransformerUtils.invokerTransformer("trim"));

O'ReillyのJakarta Commons Cookbookを強くお勧めします。

于 2009-04-13T16:58:16.023 に答える
2

私は最終的に@ericksonの答えの突然変異を使用して、次のように突然変異させました:

  • Collectionその場で変更するのではなく、新しいを返す
  • の戻り値Collectionの型と等しい型の要素を持つ を返しますFunction
  • マップの値またはリストの要素のマッピングをサポートします

コード:

public static interface Function<L, R> {
    L operate(R val);
}

public static <K, L, R> Map<K, L> map(Map<K, R> map, Function<L, R> f) {
    Map<K, L> retMap = new HashMap<K, L>();

    for (Map.Entry<K, R> e : map.entrySet()) retMap.put(e.getKey(), f.operate(e.getValue()));

    return retMap;
}

public static <L, R> List<L> map(List<R> list, Function<L, R> f) {
    List<L> retList = new ArrayList<L>();

    for (R e : list) retList.add(f.operate(e));

    return retList;
}
于 2012-03-17T01:49:41.740 に答える
2

コレクションをその場で変更できるかどうかは、コレクション内のオブジェクトのクラスによって異なります。

これらのオブジェクトが不変 (文字列) の場合、コレクションからアイテムを取得して変更するだけではなく、コレクションを反復処理し、関連する関数を呼び出して、結果の値を戻す必要があります。

于 2009-04-13T16:31:11.533 に答える
1

「マッパー」クラスを思いついた

public static abstract class Mapper<FromClass, ToClass> {

    private Collection<FromClass> source;

    // Mapping methods
    public abstract ToClass map(FromClass source);

    // Constructors
    public Mapper(Collection<FromClass> source) {
        this.source = source;
    }   
    public Mapper(FromClass ... source) {
        this.source = Arrays.asList(source);
    }   

    // Apply map on every item
    public Collection<ToClass> apply() {
        ArrayList<ToClass> result = new ArrayList<ToClass>();
        for (FromClass item : this.source) {
            result.add(this.map(item));
        }
        return result;
    }
}

私がそのように使用すること:

Collection<Loader> loaders = new Mapper<File, Loader>(files) {
    @Override public Loader map(File source) {
        return new Loader(source);
    }           
}.apply();
于 2010-06-24T08:53:54.873 に答える
1

すべてのエントリを繰り返し処理し、各文字列値をトリムする必要があります。String は不変であるため、マップに再配置する必要があります。より適切な方法は、値をマップに配置するときに値をトリミングすることです。

于 2009-04-13T16:32:09.300 に答える
-2

また、Googleコレクションを見ることができます

于 2009-04-13T19:05:22.303 に答える