按属性搜索ArrayList中的特定对象

时间:2016-01-28 12:33:43

标签: java arraylist

美好的一天,

想象一下,我有以下代码: (这些显然不是所有属性)

ArrayList

将对象添加到ArrayList:

class Owner {
    private String name;
}

class Car {
    private Owner owner;
    private String brandName;

    public boolean isClean() { // not included in the contructor
        return false;
    }

class FuelCar extends Car {
    private String fuelType;

    public boolean isClean() {
        if (fuelType.equals("Diesel")){
            return false;
        } else {
            return true;
    }
}

class ElectricCar extends Car {
    private int batteryLevel;

    public boolean isClean() {
        return true;
    }
}

示例:

ArrayList<Car> cars = new ArrayList<>();

现在的问题是:

  1. 我如何制作一个方法,所以我只列出所有价值为isClean“true”的汽车;

  2. 如何使用以下签名创建方法: public static void printCarsSpecific(ArrayList Cars,String fuelType) 所以,例如,如果我投入: printCarsSpecific( “汽油”); 打印ArrayList时只显示那些汽车。

  3. PS:这不是家庭作业。只是为了教育 我自己输入上面的代码并没有复制和粘贴,因为它会变得很大。

    我试过这些方法:

    cars.add(new Auto("Audi", new Owner("Peter")));
    cars.add(new Auto("Fiat", new Owner("Rob")));
    cars.add(new Auto(Mercedes, null));
    cars.add(new ElectricCar(10, "Opel ", new Owner("Unknown")));
    cars.add(new ElectricCar(100,"Google", new Owner("Google")));
    cars.add(new FuelCar("diesel", "Seat", new Owner("Tom")));
    cars.add(new FuelCar("gasonline", "Smart", new Owner("Marcel")));
    

    public static void printBedrijfsautosMetType(ArrayList<Auto> autos, String brandstof) {
        Iterator<Auto> iter = autos.iterator();
        while (iter.hasNext()) {
            Auto auto = iter.next();
    
            if (auto instanceof BrandstofAuto) {
                String brandstof1 = ((BrandstofAuto) auto).getBrandstof();
                if (!brandstof1.equals(brandstof) || brandstof1 == null) {
                    iter.remove();
                }
            }
            for (int i = 0; i < autos.size(); i++) {
                System.out.println(autos.get(i));
            }
    
        }
    }
    

    我想我不必删除这些项目,就像我在这里看到的例子一样。

4 个答案:

答案 0 :(得分:0)

这似乎是一项家庭作业,但我会咬人。

最简单的方法是遍历原始列表并从中选择匹配的项目。

ArrayList<Car> cleanCars = new ArrayList<Car>();
for (Car car : scars) {
    if (car.isClean()) {
        cleanCars.add(car);
    }
}

显然会创建一个对象来包装汽车集合。也许类似于CarCollection,它本身会包装像ArrayList这样的集合对象。

问题的第二部分似乎是XY Problem。为什么要将过滤汽车对象集合并将其打印出来的逻辑混合在一起? (除非你知道,如果它是家庭作业。)数据分类逻辑和表示逻辑应尽可能分开。

而不是以下内容:

public static void printCarsSpecific(ArrayList Cars, String fuelType)

为什么没有过滤汽车列表的方法?

public static ArrayList<Car> getCarsByFuelType(ArrayList cars, String fuelType)

然后,如果你有过滤后的收藏品,那么你可以用它们做你想做的事情(即打印出来)?

以下是我如何实施它。我有一个CarCollection类,它在私有ArrayList之上包装并提供您需要的访问方法。像这样。

public class CarCollection {
    private ArrayList<Car> carList;

    public void add(Car car) {
        carList.add(car);
    }

    public CarCollection getCleanCars() {
        CarCollection cleanCars = new CarCollection();
        for (Car car : this.cars) {
            if (car.isClean()) {
                cleanCars.add(car);
            }
        }
        return cleanCars;
    }

    public CarCollection getCarsByFuelType(String fuelType) {
        CarCollection filteredCars = new CarCollection();
        for (Car car : this.cars) {
            if (car instanceof FuelCar) {
                if (car.fuelType.equals(fuelType)) {
                    filteredCars.add(car);
                }
            }
        }
        return filteredCars;
    }
}

答案 1 :(得分:0)

汽车的硬编码过滤列表:

public static List<Car> filterCleanFuelCars(List<Car> cars) {
    List<Car> filtered = new LinkedList<>();
    for (Car c : cars) {
        if (c instanceof FuelCar) {
            FuelCar fuelCar = (FuelCar) c;
            if (fuelCar.isClean()) {
                filtered.add(fuelCar);
            }
        }
    }
    return filtered;
}  

根据自定义条件过滤汽车列表(硬编码条件由谓词替换):

public static List<Car> filterCars(List<Car> cars, Predicate<Car> condition) {
    List<Car> filtered = new LinkedList<>();
    for (Car c : cars) {
        if (condition.apply(c)) {
            filtered.add(c);
        }
    }
    return filtered;
}  

与上面Stream相同:

public static List<Car> filterCars(List<Car> cars, Predicate<Car> condition) {
    return cars.stream()
               .filter(condition)
               .collect(Collectors.toList());
}

使用示例:

List<Car> cleanCars = filterCars(cars, new Predicate<Car>() {
    @Override
    public boolean apply(Car c) {
        return c.isClean();
    }
});

这可以通过 lambda表达式(替换匿名类)缩短

List<Car> cleanCars = filterCars(cars, (Car c) -> c.isClean());

如果您需要更多行来决定过滤器是否适用于汽车,您可以写:

List<Car> cleanFuelCars = filterCars(cars, (Car c) -> {
    if (c instanceof FuelCar) {
        FuelCar fuelCar = (FuelCar) c;
        return c.isClean();
    }
    return false;
});

由于并非列表中包含的所有汽车都延伸FuelCar,您首先需要检查汽车是否为FuelCar的实例,之后,您需要将此汽车投入FuelCar }输入并最终检查fuelType属性的值。

注意,使用String运算符无法检查==值是否相等,因为String不是原始数据类型,如int, long, float, double总是按值传递(当您将int传递给方法时,int将被复制到方法的局部变量 - 参数中。通过String比较==之类的对象只检查引用的相等性,即检查两个对象是否指向内存中的同一对象 - 对象总是通过引用传递(地址)。简而言之,当你使用字符串时总是使用equals方法。

public static void printCarsSpecific(List<Car> cars, String fuelType) {
    for (Car c : cars) {
        if (c instanceof FuelCar) {
            FuelCar fuelCar = (FuelCar) c;
            if (fuelCar.fuelType.equals(fuelType)) {
                System.out.println(fuelCar);
            }
        }
    }
}

您还可以使用printCarsSpecific方法将filterCars重写为更通用的方法:

public static void printCarsSpecific(List<Car> cars, Predicate<Car> p) {
    List<Car> filtered = filterCars(cars, p);
    for (Car c : filtered) {
        System.out.println(c);
    }
}

要打印汽油燃料汽车,你会写:

printCarsSpecific(cars, (Car c) -> {
    if (c instanceof FuelCar) {
        FuelCar fuelCar = (FuelCar) c;
        retur fuelCar.fuelType.equals("gasoline");
    }
    return false;
});

答案 2 :(得分:0)

如果您使用的是Java 8,则可以使用花哨的流,例如:

List<Car> cleanCars = carList.stream().filter(car -> car.isClean()).collect(Collectors.toList());

List<Car> carsFilteredOnFuelType = carList.stream().filter(car -> fueltype.equals(car.fueltype)).collect(Collectors.toList));

答案 3 :(得分:0)

如果您不需要,我建议您不要将变量声明为ArrayList。抽象越大,代码就越通用,因此程序就越强大。看看这个例子:

ArrayList<Car> cars = new ArrayList<>();

为什么你要说carsArrayList?您只需在实例化时指定确切的类型。这是优越的:

AbstractList<Car> cars = new ArrayList<Car>();

ArrayList implements AbstractList您可能稍后决定将cars切换为其他类型的AbstractList实施。

另外,阅读/观看一些教程,因为即使使用最基本的语法,你也在苦苦挣扎。

现在让我们看看你的问题。您的第一个问题是要求仅列出清除cars的方法。此任务不是原子的,您需要分离任务。首先,获得cars的干净子集很好。即使您不打算列出它们,这种类型的任务也很有用。所以,让我们独立实施它:

public static AbstractList<Car> getCleanCars(AbstractList<Car> cars) {
    AbstractList<Car> cleanCars = new ArrayList<Car>();
    for (Car car : cars) {
        if (car.isClean()) {
            cleanCars.add(car);
        }
    }
    return cleanCars;
}

然后你需要一个显示cars的方法。我们假设它看起来像这样:

public static void displayCars(AbstractList<Car> cars) {
    //Display the cars
}

您需要拨打displayCars,如下所示:Car.displayCars(Car.getCleanCars(cars))

您的第二个问题是不合逻辑的,因为您想使用单个参数调用使用两个参数声明的方法。由于你的代码充满了错误,它实际上是不可读的,所以我无法帮助你,但是,如果某种燃料类型可以从Car对象确定,那么你需要迭代列表如上所示的汽车而不是呼叫isClean,您需要使用{{1}将Car的燃料类型与String进行比较。方法。