我有一个主要的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;
}
}
}
答案 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
。