Возврат подсписка на основе переменной-члена или функции отображения - PullRequest
1 голос
/ 20 марта 2012

У меня есть список pojo's List<Pojo> pojoList; и pojo.getColour(); возвращает экземпляр Enum.

И я хочу сделать это:

List<Pojo> newlist = new ArrayList<Pojo>();
for(Pojo pojo:pojoList){
  if(pojo.getColour() == Colour.Red){
    newList.add(pojo);
  }
}

Я мог бы видеть, как я использую аналогичную функцию для списков других типов, поэтому вместо повторения большого количества кода это способ сделать его универсальным и / или функциональным? Чтобы я мог создавать списки разных типов на основе другого правила?

Ответы [ 4 ]

6 голосов
/ 20 марта 2012

Прежде всего, я должен отметить, что если вы просто хотите новый ArrayList, содержащий соответствующие элементы, то способ, которым вы сделали это в своем примере, вполне подойдет. Пока у Java нет лямбда-выражений, вы не станете проще или лучше выглядеть, чем это.

Поскольку вы пометили это как , вот как вы могли бы сделать это с Гуавой. Вы в основном фильтруете исходный список по составу предиката (== Color.Red) и функции (pojo.getColour()). Так что, если у вас был статический финал Function<Pojo, Colour> с именем COLOUR на Pojo (например, так):

public static final Function<Pojo, Colour> COLOUR =
    new Function<Pojo, Colour>() {
      @Override public Colour apply(Pojo input) {
        return input.getColour();
      }
    };

вы можете создать эту комбинацию так:

Predicate<Pojo> isRedPojo = Predicates.compose(
    Predicates.equalTo(Colour.Red), Pojo.COLOUR);

Затем можно создать отфильтрованное представление исходного списка:

Iterable<Pojo> redPojos = Iterables.filter(pojoList, isRedPojo);

И вы можете скопировать это отфильтрованное представление в ArrayList, если хотите:

List<Pojo> copy = Lists.newArrayList(redPojos);
1 голос
/ 20 марта 2012

сделать общий интерфейс фильтра

public interface Filter<T>{
     public boolean match(T item);
}

создать метод с использованием фильтра

public <T> List<T> getFilteredList(List<T> oldList, List<T> filter){
   List<T> newlist = new ArrayList<T>();

   for(T item:oldList){
      if(filter.match(item)){
         newlist.add(item);
      }
   }

   return newlist;
} 

собрать все вместе

List<Pojo> myList = .. 

List<Pojo> redList = getFilteredList(myList,new Filter<Pojo>(){
      public boolean match(Pojo item){ return item.isRed()};
});

List<Pojo> blueList = getFilteredList(myList,new Filter<Pojo>(){
      public boolean match(Pojo item){ return item.COLOR== Color.BLUE};
 }); 
1 голос
/ 20 марта 2012

В зависимости от того, как часто вы его используете / сколько разных фильтров (только красный, только зеленый и т. Д.) Вы используете, может иметь смысл создать интерфейс фильтра - если это только проверка isRed, то это, вероятно, слишкоммного кода, и вам лучше использовать простой статический метод.

Хорошая вещь в этом проекте - вы можете использовать его с любыми объектами, которые хотите фильтровать (см. пример со строкой ниже).

public static void main(String[] args) {
    List<Pojo> originalList = Arrays.asList(new Pojo(true), new Pojo(false), new Pojo(false));
    List<Pojo> filteredList = Utils.getFilteredList(originalList, new Filter<Pojo>() {
        @Override
        public boolean match(Pojo candidate) {
            return candidate.isRed();
        }
    });
    System.out.println(originalList.size()); //3
    System.out.println(filteredList.size()); //1

    //Now with strings
    List<String> originalStringList = Arrays.asList("abc", "abd", "def");
    List<String> filteredStringList = Utils.getFilteredList(originalStringList, new Filter<String>() {
        @Override
        public boolean match(String candidate) {
            return candidate.contains("a");
        }
    });
    System.out.println(originalStringList.size()); //3
    System.out.println(filteredStringList.size()); //2
}

public static class Utils {
    public static <T> List<T> getFilteredList(List<T> list, Filter<T> filter) {
        List<T> selected = new ArrayList<>();
        for (T t : list) {
            if (filter.match(t)) {
                selected.add(t);
            }
        }
        return selected;
    }
}

public static class Pojo {
    private boolean isRed;

    public Pojo(boolean isRed) {
        this.isRed = isRed;
    }

    public boolean isRed() {
        return isRed;
    }
}

public interface Filter<T> {

    /**
    * When passed a candidate object, match returns true if it matches the filter conditions,
    * or false if it does not.
    * @param candidate the item checked against the filter
    * @return true if the item matches the filter criteria
    */
    boolean match(T candidate);
}
1 голос
/ 20 марта 2012

Вы должны заставить свой тип реализовать общий интерфейс для проверки:

public interface Candidate {
  public boolean isAddable();
}

Цикл тогда будет выглядеть так

List<Candidate> newlist = new ArrayList<Candidate>();
for(Candidate pojo:pojoList){
 if(pojo.isAddable()){
   newList.add(pojo);
 }
}

и класс Pojo должен был бы реализовать интерфейс:

public class Pojo implments Candidate {

  // ...

  @Override
  public boolean isAddable() {
    return isRed();
  }
}
...