如何通过具有boolean变量定义的3种过滤器类型的ArrayList进行过滤?

时间:2019-03-24 18:45:56

标签: java arraylist

我有一个主要的ArrayList<Car> cars,我正在尝试以三种不同的方式进行过滤。每个过滤器可以单独使用,也可以一起使用。

因此,如果存在三个过滤器:x,y和z,并且只有x和y为真,则新的数组列表将考虑过滤器x和y,并且将显示每个条目。如果x,y和z均为true,则将通过所有三种方法过滤主数组列表“ cars”,并创建一个新的数组列表,然后显示所有过滤后剩下的内容。

每个过滤器都有布尔型实例变量,每当调用特定过滤器的方法时,这些变量都设置为true。例如,如果要过滤cars数组列表以查看汽车是否为电动汽车,则可以在filterElectric = true方法的开始处设置public void filterByElectric(),然后添加我在其中使用for循环的代码,检查数组列表的每个索引位置中的每个Car对象是否是电动的。

我知道我可以简单地做一个大的if语句,让我说if (filterElectric == true),然后显示包含过滤后的汽车的新数组列表,而且我知道我可以使用&&来使用多个一次过滤(如果为真),然后将新创建的数组列表附加在一起,并使用for循环显示每个新过滤的条目,但是这样做将意味着我必须为所有情况创造条件。

我如何能够首先检查三个过滤器中的哪个过滤器为真,然后在知道哪个过滤器变量设置为true以后才能将这两个过滤器列表一起显示?


    public void displayEverything() {
    if (filX == true && filY == true && filZ == true) {
        // append all filtered lists and then print newly created
        // list to system

        filtered.addAll(filX);
        filtered.addAll(filY);
        filtered.addAll(filZ);

        for (Car a : filtered) {
            System.out.println(a.disp());
        }

    } else if (filX == true && filY == true & filZ == false) {
        filtered.addAll(filX);
        filtered.addAll(filY);

        for (Car a : filtered) {
            System.out.println(a.disp());
        }
        // then it keeps going.... 
        // is there a faster way to do this 
        // instead of writing all conditions with &&'s?
    }
}


public void filterX() {
    filX = true;

    for (Car a : cars) {
        if (a.getWhatever() == 1) {
            xList.add(a);
        } else {
            break;
        }
    }
}

public void filterY() {
    filY = true;

    for (Car a : cars) {
        if (a.getSomething() == true) {
            yList.add(a);
        } else {
            break;
        }
    }
}

public void filZ(double a, double b) {
    filZ = true;

    for (Car a : cars) {
        if (a.getP() >= a && a.getP() <= b) {
            zList.add(a);
        } else {
            break;
        }
    }
}

5 个答案:

答案 0 :(得分:1)

如果您希望代码尽可能短,则可以这样做:

public static List<Car> filter(
    List<Car> allCars,
    boolean onlyElectric,
    boolean onlyAllWheelsDrive,
    boolean onlyAutomatic)
{
    return allCars.stream()
        .filter((Car car) -> !onlyElectric || car.isElectric())
        .filter((Car car) -> !onlyAllWheelsDrive|| car.isAllWheelsDrive())
        .filter((Car car) -> !onlyAutomatic|| car.isAutomatic())
        .collect(Collectors.toList());
}

!onlyElectric || …最初看起来有些奇怪。可以用另一种方式写:

    .filter((Car car) -> onlyElectric ? car.isElectric() : true)

可以更轻松地将其翻译成人类可以理解的语言:如果选择了“ onlyElectric”过滤器,请检查汽车是否真的是电动的。如果未选择,则返回true,这意味着过滤器会接受每辆汽车。

在编写此代码的那一刻,这将是有意义的。再过几天,当您再次添加另一个过滤器时,您可能会问自己:3个布尔参数中的哪个是哪个,为什么它们按此顺序排列?另一种解决方案是使用enum代替这些布尔值。

public enum CarFilter {
    Electric, AllWheelsDrive, Automatic
}

public static List<Car> filter(
    List<Car> allCars,
    CarFilter... filters)
{
    EnumSet<CarFilter> set = EnumSet.noneOf(CarFilter.class);
    Collections.addAll(set, filters);

    return allCars.stream()
        .filter((Car car) -> !set.contains(CarFilter.Electric) || car.isElectric())
        .filter((Car car) -> !set.contains(CarFilter.AllWheelsDrive) || car.isAllWheelsDrive())
        .filter((Car car) -> !set.contains(CarFilter.Automatic) || car.isAutomatic())
        .collect(Collectors.toList());
}

这样,您可以像这样调用方法:

filter(allCars, CarFilter.Electric, CarFilter.Automatic);

此代码肯定包含比以下更多的信息:

filter(allCars, true, false, true);

答案 1 :(得分:0)

可能快速找到所需的解决方案。

从汽车开始:

package so.car;

public class Car {
    private String name;
    private boolean electric;
    private boolean awd;
    private boolean automatic;

    public Car(String name, boolean electric, boolean awd, boolean automatic) {
        this.name = name;
        this.electric = electric;
        this.awd = awd;
        this.automatic = automatic;
    }

    public boolean isElectric() {
        return electric;
    }

    public void setElectric(boolean electric) {
        this.electric = electric;
    }

    public boolean isAwd() {
        return awd;
    }

    public void setAwd(boolean awd) {
        this.awd = awd;
    }

    public boolean isAutomatic() {
        return automatic;
    }

    public void setAutomatic(boolean automatic) {
        this.automatic = automatic;
    }

    @Override
    public String toString() {
        return "Car [name=" + name + "]";
    }

}

然后要处理一次运行多个过滤器的问题:

package so.car;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Function;

public class CarFilters {
    private Map<String, Function<Car, Boolean>> filters;

    public CarFilters(Map<String, Function<Car, Boolean>> filters) {
        this.filters = filters;
    }

    public List<String> getPassingFilterNames(Car car) {
        List<String> passingFilterNames = new ArrayList<>();

        for (Entry<String, Function<Car, Boolean>> entry : filters.entrySet()) {
            String filterName = entry.getKey();
            Function<Car, Boolean> predicateFunction = entry.getValue();

            if (predicateFunction.apply(car)) {
                passingFilterNames.add(filterName);
            }
        }

        return passingFilterNames;
    }
}

最后是一个简单的驱动程序类:     打包so.car;

import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Function;
import java.util.stream.Collectors;

public class Test {
    public static void main(String[] args) {
        Map<String, Function<Car, Boolean>> filterNameMap = new HashMap<>();
        filterNameMap.put("Electric", car -> car.isElectric());
        filterNameMap.put("All Wheel Drive", car -> car.isAwd());
        filterNameMap.put("Automatic Transmission", car -> car.isAutomatic());

        CarFilters carFilters = new CarFilters(filterNameMap);

        Car _0 = new Car("zero", true, true, true);
        Car _1 = new Car("one", true, false, true);
        Car _2 = new Car("two", false, false, true);
        Car _3 = new Car("three", true, true, true);

        List<Car> cars = new ArrayList<>();
        cars.add(_0);
        cars.add(_1);
        cars.add(_2);
        cars.add(_3);

        Map<List<String>, List<Car>> filtersAndCars = cars.stream()
                                                          .map(car -> {
                                                              List<String> filters = carFilters.getPassingFilterNames(car);

                                                              return new SimpleEntry<>(filters, new ArrayList<>(Arrays.asList(car)));
                                                          })
                                                          .collect(Collectors.toMap(Entry::getKey, Entry::getValue, (l1, l2) -> {
                                                              l1.addAll(l2);
                                                              return l1;
                                                          }));

        System.out.println(filtersAndCars);
    }
}

这将产生:

[Automatic Transmission]=[Car [name=two]],
[Automatic Transmission, Electric]=[Car [name=one]]
[All Wheel Drive, Automatic Transmission, Electric]=[Car [name=zero], Car [name=three]]

答案 2 :(得分:0)

您可以基于要应用的过滤逻辑来构建谓词,只需使用此谓词来过滤流:

     public Predicate<Car> filter = car ->  {
        boolean filter = true;

        if (isfilterEletricOn()) {
            filter = filter && car.isEletric();
        }

        if (isfilterOffRoadOn()) {
            filter = filter && car.isOffRoad();
        }

        if (isfilterSportOn()) {
            filter = filter && car.isSport();
        }

        return filter;
    };

    cars.stream().filter(filter).collect(Collectors.toList());

答案 3 :(得分:0)

您可以执行以下操作:

public static Predicate<Car> filteringAll(boolean filterToyota, boolean filterAudi) {
        return p -> (p.getManufacturer().getName().equals("Toyota") && filterToyota) || (p.getManufacturer().getName().equals("Audi") && filterAudi);
    }

并在您的代码中使用它,例如:

List<Car> listOfFilteredCars = listOfCars.stream().filter(filteringAll(false, true)).collect(Collectors.toList());

因此,如果要过滤奥迪和丰田,则将它们的两个过滤器都设置为true,如果只想过滤Toyota汽车,则将Toyota过滤器设置为true,而Audi过滤器设置为false。

完整的运行代码:

  

主班

public class Main {

    List<Car> listOfCars = new ArrayList<>();

    public static void main(String[] args) {
        List<Car> listOfCars = new ArrayList<>();
        listOfCars.add(new Car(Manufacturer.TOYOTA, "Toyota A", 90));
        listOfCars.add(new Car(Manufacturer.TOYOTA, "Toyota B", 35));
        listOfCars.add(new Car(Manufacturer.AUDI, "Audi B", 64));
        listOfCars.add(new Car(Manufacturer.MERCEDES, "Mercedes C", 464));
        listOfCars.add(new Car(Manufacturer.TOYOTA, "Toyota C", 33));
        listOfCars.add(new Car(Manufacturer.AUDI, "Audi A", 75));
        listOfCars.add(new Car(Manufacturer.TOYOTA, "Toyota C", 23636));

        List<Car> listOfFilteredCars = listOfCars.stream().filter(filteringAll(false, true, false)).collect(Collectors.toList());

        System.out.println(listOfFilteredCars);
    }

    public static Predicate<Car> filteringAll(boolean filterToyota, boolean filterAudi, boolean filterMercedes) {
        return p -> (p.getManufacturer().equals(Manufacturer.TOYOTA) && filterToyota) || (p.getManufacturer().equals(Manufacturer.AUDI) && filterAudi) || (p.getManufacturer().equals(Manufacturer.MERCEDES) && filterMercedes) ;
    }

}

  

汽车课

public class Car {

    private Manufacturer manufacturer;
    private String nameOfTheCar;
    private double price;

    public Car() {
    }

    public Car(Manufacturer manufacturer, String nameOfTheCar) {
        this.manufacturer = manufacturer;
        this.nameOfTheCar = nameOfTheCar;
    }

     public Car(Manufacturer manufacturer, String nameOfTheCar, double price) {
        this.manufacturer = manufacturer;
        this.nameOfTheCar = nameOfTheCar;
        this.price = price;
    }

    public Manufacturer getManufacturer() {
        return manufacturer;
    }

    public String getNameOfTheCar() {
        return nameOfTheCar;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }



    @Override
    public String toString() {
        return "Manufacturer: " + getManufacturer() + ", name: " + getNameOfTheCar();
    }

}

  

制造商类别

public enum Manufacturer {

    AUDI, MERCEDES, TOYOTA;

}

答案 4 :(得分:0)

对于更动态的解决方案,您可以创建一个int func(const std::array<int, 5>& values) { return std::accumulate(values.begin(), values.end(), 0) / values.size(); } 类,该类具有一个MyFilter属性和一个active谓词:

filter

现在,您可以创建(活动)过滤器的动态列表:

public class MyFilter<T> {
    private boolean isActive;
    private Predicate<T> filter;
    // constructor and/or getter and setter
}

最后,您可以过滤List<MyFilter<MyObject>> filters = Arrays.asList( new MyFilter<>(true, MyObject::isA), new MyFilter<>(false, MyObject::isB), new MyFilter<>(true, MyObject::isC) );

List<MyObject>

要使整体内容更具可读性,您可以在过滤器中添加一个List<MyObject> result = objects.stream() .filter(o -> filters.stream().filter(MyFilter::isActive).allMatch(f -> f.getFilter().test(o))) .collect(Collectors.toList()); 方法:

test

并使用以下方法过滤列表:

public boolean test(T object) {
    return !isActive || filter.test(object);
}

如果您只想匹配一个过滤器,则可以使用List<MyObject> result = objects.stream() .filter(o -> filters.stream().allMatch(f -> f.test(o))) .collect(Collectors.toList()); 代替anyMatch。要取消结果,您可以使用allMatch