3

リストをフィルタリングするかなり単純なメソッドを実装しようとしています。これはファイル オブジェクトのリストであり、.asp で終わるファイルが 1 つだけ存在する必要があります。そのファイルをリストから除外します。このファイルを実際にリストから削除したくないことに注意してください。そのリストの特定の反復で無視できるようにしたいだけです。

私の元の(総当たり)実装は次のようになりました。

public List<File> getSurveyFiles() throws Exception {
    List<File> surveyFiles = new ArrayList<File>(files.size() - 1);

    for ( File f : files ) {
        if ( !f.getName().endsWith(".asp") ) {
            surveyFiles.add(f);
        }
    }

    return surveyFiles;
}

それは機能しますが、2 つ目のリストを作成し、1 つのリストから別のリストに多くのコピーを行っているという事実に、非常に無駄を感じます。

私がいじった別のオプションは、guava-libraries (http://code.google.com/p/guava-libraries/) を使用し、次のようにフィルター機能を利用することです。

public class SurveyFileControllerPredicate implements Predicate<File> {

    @Override
    public boolean apply(File file) {
        return file.getName().endsWith(".asp");
    }
}

...

public Iterable<File> getSurveyFiles() throws Exception {

    return Iterables.filter(
        files,
        Predicates.not(new SurveyFileControllerPredicate())    
    );

}

フィルターの実装は、事前ではなく反復時に .asp ファイルを削除するため、このコードには 2 番目のリストを作成しないという利点がありますが、コードがより複雑になると感じています。

私が考慮していない他のより単純な実装はありますか?

物事の全体的なスキームでは、私がどの実装を選択するかはおそらく問題ではありません。他の開発者がこれにどのように取り組み、どのオプションを選択するのか、私はただ興味があります.

ありがとう。

4

3 に答える 3

5

toString()次の関数を使用して、正規表現一致述語を作成できます。

public Iterable<File> getSurveyFiles() {
  return Iterables.filter(files, Predicates.compose(
      Predicates.not(Predicates.containsPattern("\\.asp$")),
      Functions.toStringFunction()));
}
于 2012-10-29T15:48:06.207 に答える
2

ある時点で、次のような問題を処理する 2 つの非常に一般的なヘルパー クラスを自分で作成しました。

public abstract class IteratorFilter<E> implements Iterator<E> {
  private final Iterator<E> iterator;

  private E next = null;

  public IteratorFilter(Iterator<E> iterator) {
    this.iterator = iterator;
  }

  @Override
  public boolean hasNext() {
    if (next!=null) return true;
    while (iterator.hasNext()) {
      next = iterator.next();
      if (keep(next)) return true;
    }
    return false;
  }

  @Override
  public E next() {
    if (next==null)
      do next = iterator.next(); while (!keep(next));
    E result = next;
    next = null;
    return result;
  }

  @Override
  public void remove() {
    iterator.remove(); // Specs require: throw new UnsupportedOperationException();
  }

  protected abstract boolean keep(E item);
}

と:

public abstract class IterableFilter<T> implements Iterable<T> {

  private final Iterable<T> iterable;

  public IterableFilter(Iterable<T> iterable) {
    this.iterable = iterable;
  }

  @Override
  public Iterator<T> iterator() {
    return new IteratorFilter<T>(iterable.iterator()) {
      @Override
      protected boolean keep(T item) {
        return IterableFilter.this.keep(item);
      }
    };
  }

  protected abstract boolean keep(T item);
}

これらを使用すると、次のように簡単に実行できます。

public Iterable<File> getSurveyFiles() {
  return new IterableFilter<File>(files) {
    @Override
    protected boolean keep(File item) {
      return !item.getName().endsWith(".asp");
    }
  };
}

述語オブジェクトを追跡する必要がなく、新しいライブラリ依存関係を導入しないことを除いて、これは基本的に Guava Predicate メソッドと同じアプローチです。

于 2012-10-29T14:50:11.647 に答える
0

(フィルター処理されたコピーまたはビューを返す関数を記述するのではなく) 反復サイトでフィルター処理を記述したい場合は、Java 8 ストリームを使用すると、これが非常に簡単になります。

files.stream().filter(f -> !f.getName().endsWith(".asp")).forEachOrdered(f -> {
    //process file f
});

このフィルタリングをいくつかの場所でのみ行う場合、フィルタリングされたコピーまたはビューを返すメソッドを記述するよりも簡潔になり、フィルタリング操作をフィルタリングされたリストが使用される場所の近くに保ちます。このフィルタリングを多くの場所で行い、後でリストを別の方法でフィルタリングしたい場合は、メソッドを作成する方がよいかもしれませんが、Stream を返すメソッドにすることもできます。

public Stream<File> getSurveyFiles() {
    return files.stream().filter(f -> !f.getName().endsWith(".asp"));
}

forEachOrderedその後、戻り値を呼び出すことができます。ストリーム以外の操作が必要な場合は、呼び出しiteratorて反復子.collect(Collectors.toList())を取得するか、フィルター処理されたリストのコピーを取得します。

于 2014-10-05T00:07:07.690 に答える