-2

Good day,

Imagine I have the following code: (These are obviously not all the attributes)

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;
    }
}

The objects are added to an ArrayList:

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

Examples:

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")));

Now the questions are:

  1. How can I make a method so I only list all cars which have the value isClean "true";

  2. How can I make a method with the following signature: public static void printCarsSpecific(ArrayList Cars, String fuelType) So for example if I put in: printCarsSpecific("gasoline"); that only those cars will be shown when printing the ArrayList.

PS: it's not homework. Just for education I typed the code above by myself and didnt copy and paste because it would become way to large.

I tried these methods:

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));
        }

    }
}

and

   public static void printSchoneAutos(ArrayList<Auto> autos) {
        Iterator<Auto> iter = autos.iterator();
        while (iter.hasNext()) {
            Auto auto = iter.next();
            if (auto instanceof BrandstofAuto) {
                boolean isschoon = ((BrandstofAuto) auto).isSchoon();
                boolean isschoon3 = auto.isSchoon();
                if (isschoon3 == false || isschoon == false) {
                    iter.remove();
                }
            }
            for (int i = 0; i < autos.size(); i++) {
                System.out.println(autos.get(i));
            }
        }
    }

I guess I don't have to delete these items as i've seen by examples under here.

  • Have you tried anything yet? – proskor Jan 28 '16 at 12:41
  • @R.Schouten You should at least indent your codes first. Further more, your syntax is wrong and why are words like `class` and `private` in uppercase? It seems to me you don't even know the very basics. Perhaps you should post what you have tried so far. – user3437460 Jan 28 '16 at 12:41
  • 3
    This does seem suspiciously like a homework assignment... – Tom Morris Jan 28 '16 at 12:41
  • @TomMorris homework assignments can be the subject of valid StackOverflow questions, provided the OP includes a summary of the work he/she has done so far to solve the problem, and a description of the difficulty he/she is having solving it. – RealSkeptic Jan 28 '16 at 13:03
  • [Don't compare strings using `==`](http://stackoverflow.com/q/513832/4125191). And when you present "code", it should be code that compiles correctly (braces are properly closed, comments are preceded by `//` rather than `==` (in Java)), and the code should be indented properly. – RealSkeptic Jan 28 '16 at 13:04
  • As I wrote in my answer, objects are passed by reference, that is `printSchoneAutos(ArrayList autos)` will modify original collection of your cars, since autos is just reference on object that is passed to method = your cars collection. Therefore you should not delete objects in this method if you don't want to change the original collection. – matoni Jan 28 '16 at 18:45

4 Answers4

0

This seems like a homework assignment, but I'll bite.

The simplest way is to iterate through the original list and select items from it that match.

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

One would obviously create an object to wrap the collection of cars in. Perhaps something like CarCollection, which would itself wrap a collection object like ArrayList.


The second part of the question seems like an XY Problem. Why would you want to mix together the logic of filtering your collection of car objects and printing them out? (Except, you know, if it is a homework assignment.) Data sorting logic and presentation logic should be separated out wherever possible.

Instead of the following:

public static void printCarsSpecific(ArrayList Cars, String fuelType)

Why not have a method that filters the list of cars?

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

Then when you have that filtered collection, then you can do what you want with them (i.e. print them out)?

Here's how I'd implement it. I'd have a CarCollection class which wraps and provides access methods you need on top of a private ArrayList. Like this.

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;
    }
}
Tom Morris
  • 3,979
  • 2
  • 25
  • 43
0

Hard-coded filtering list of cars:

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;
}  

Filtering list of cars based on custom condition (hard-coded condition is replaced by predicate):

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;
}  

The same as above with Stream:

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

Example of usage:

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

This can be shortened via lambda expression (substitution for anonymous class)

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

If you need more lines to decide whether the filter applies for the car, you can write:

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

Since not all cars contained in list extends FuelCar, you need to check at first, whether the car is instance of FuelCar, after that, you need to cast this car into FuelCar type and finally check value of the fuelType attribute.

Note, that String value can not be checked for equality by using == operator, since String is not primitive data type like int, long, float, double which are always passed by value (when you pass int to a method, then int is copied into local variable of the method - parameter). Comparing objects like String via == checks only equality of references, that is, checks if two objects are pointing to the same object in memory - objects are always passed by references (addresses). In short, when you work with string always use equals method.

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);
            }
        }
    }
}

You can also rewrite printCarsSpecific to more generic method by using filterCars method:

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

To print gasoline fuel cars you would write:

printCarsSpecific(cars, (Car c) -> {
    if (c instanceof FuelCar) {
        FuelCar fuelCar = (FuelCar) c;
        retur fuelCar.fuelType.equals("gasoline");
    }
    return false;
});
matoni
  • 2,479
  • 21
  • 39
0

If you are using java 8 you could use fancy streams such as :

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));
Louis F.
  • 2,018
  • 19
  • 22
0

I would advise you to not declare variables as ArrayList if you do not need to do so. The bigger the abstraction, the more general is your code and thus the more powerful your program is. Look at this example:

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

Why do you have to say that cars will be ArrayList? You need to specify the exact type only at instantiation. This is superior:

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

ArrayList implements AbstractList and you might decide later to switch cars to another type of AbstractList implementation.

Also, read/watch some tutorials, as you are struggling even with the most basic syntax.

And now let us see your questions. Your first question asks for a way to list out only clean cars. This task is not atomic and you need to separate the tasks. First of all, it is nice to get the clean subset of cars. This type of task could be useful even if you are not intending to list them. So, let us implement it independently:

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;
}

And then you need a method which displays cars. Let's suppose it looks like this:

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

You will need to call displayCars like this: Car.displayCars(Car.getCleanCars(cars))

Your second question is illogical, since you want to call a method declared with two parameters using a single parameter. Since your code is full of errors, it is really unreadable, so I am not able to help you with that, however, if somehow a fuel type can be determined from a Car object, then you need to iterate the list of cars as shown above and instead of calling isClean, you will need to compare the fuel type of the Car as a String to the parameter you are receiving, using the .equals() method.

Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175