I have a List of objects. I want to iterate through this list of objects and process some subsets of objects based on a condition and finally create a new list of objects with some processed objects being eliminated.
What is the best way to do this.?
Example:
Actual object : List<Cars>
Iterate through this list and find Cars with same speed.
In that smaller set of Cars, the ones which are of same model are to be eliminated.
Finally after elimination I get the new list.
The Google Guava libraries have:
Iterables.filter(cars, new Predicate<Car>() {
#Override
public boolean apply(Car car) {
//return true or false depending on whether you
// want this car to remain in the list
}
}
You can also use an intermediate Set - i.e.
cars = new ArrayList<Car>(new HashSet<Car>(cars));
where you have properly implemented hashCode and equals. This option is viable if this is the identity of your car.
You can also use an iterator:
for (Iterator<Car> it = cars.iterator(); it.hasNext();) {
Car car = it.next();
if (conditions here) {
it.remove();
}
}
By the way, I'm aware that the above examples don't solve your problem completely - you should still consider what to iterate within the outer loops.
If you are looking to do custom equals comparing, then you should define a Comparator<Car> and then just loop through the Cars.
List<Car> originalList;
Comparator<Car> c = new CarSpeedComparator();
List<Car> result = carFilter(originalList, c);
/// Below is the filter method
public static List<Car> carFilter(List<Car> original, Comparator<Car> comp)
List<Car> result = new ArrayList<Car>();
// Process each car
for (Car car: original) {
boolean containsC = false;
// now we check each car in the result
// to see if we already have an equivalent car
for (int i = 0; i < result.size(); i++) {
// if the two cars are equivalent under the rules
// then we already have that car in the list
if (comp.compare(result.get(i), car) == 0) {
containsC = true;
break;
}
}
// if the result does not contain an equivalent car,
// add it to the list
if (!containsC) result.add(car)
}
return result;
}
//// Implementation of one of the necessary comparators
public class CarSpeedComparator implements Comparator<Car> {
public int compare(Car c1, Car c2) {
return c1.getSpeed() - c2.getSpeed();
}
}
The resulting list will only contain one car of each speed.
It sounds like what you might want to do first is index the cars in your list by speed. Once you've done that, it might be easier to do the rest of the processing you're looking for. Guava's Multimaps are good for this:
ImmutableListMultimap<Integer, Car> speedIndex = Multimaps.index(cars,
new Function<Car, Integer>() {
public Integer apply(Car from) {
return from.getSpeed();
}
});
Now speedIndex will be a multimap that lets you do something like this:
for (Integer speed : speedIndex.keySet()) {
ImmutableList<Car> carsWithSpeed = speedIndex.get(speed);
// Do stuff
}
This gives you groupings of all cars in the original list that have the same speed. You could then do whatever processing on them you wanted. You might want to index this group of cars by model, giving you groupings of cars that have both the same speed and model. You could then remove those cars from the original list if you wanted. Alternatively, if you don't want to modify the original list at all but just get a copy of the list with a set of cars removed, you could add each car to be removed to a Set, then get the copy with those cars removed like this:
Set<Car> carsToRemove = ...;
List<Car> filteredList = Lists.newArrayList(Iterables.filter(cars,
Predicates.not(Predicates.in(carsToRemove))));
If you did this repeatedly on big lists, you'd want to be more efficient. Keep a list of objects, but also keep separate lists for each model of car; Hashtable<String, List> models. That way, you already have the model part done for future sorts. It takes slightly more memory, but notably less time to search through.
To me it looks like the OP just wants a unique set of (model,speed) pair. If so, here is a easy way to do it:
class Car {
private final String model;
private final int speed;
public int hashCode(){
return model.hashCode() + speed;
}
public boolean equals(Object obj){
//check on null/different class omitted.
Car other = (Car)obj;
return this.model.equals(obj.model) && this.speed == other.speed;
}
}
then
Set<Car> cars = new HashSet<Car>(originalListOfCars);
Related
Im working on this really small project, I've got an arraylist of car objects and im trying to print all the cars out in price ascending order. When i look around online every seems to be doing it with an array rather than are arraylist?
Any ideas on how i can make this possible with an array list? Below is the code i have.
public ArrayList<Car> sortPriceAcending(ArrayList<Car> cars) {
ArrayList<Car> sortedCars = new ArrayList<Car>();
Car temp;
for (int j = 0; j < cars.size() - 1; j++) {
for (int i = 0; i < cars.size() - 1; i++) {
Car car = (Car) cars.get(i);
Car car1 = (Car) cars.get(i + 1);
if (car.getPrice() > car1.getPrice()) {
temp = car;
cars.get(i) = cars.get(i + 1);
cars.get(i + 1) = temp;
sortedCars = cars;
}
}
}
return sortedCars;
}
There are many sorting algorithms available. Java itself already offers a good one and you can just use it with Collections#sort (official documentation). The method accepts any kind of List and ArrayList is one of them.
Therefore you need to define on which order you want to sort, you want to sort by prices.
You can define a natural ordering on your cars by implementing Comparable like this:
public class Car implements Comparable<Car> {
#Override
public int compareTo(Car other) {
return Integer.compare(this.getPrice(), other.getPrice());
}
// The other stuff of the car class
}
After that you can just use Collections.sort(cars) and it will sort based on this natural ordering you have defined.
However for general cars it might not be the best idea that their natural ordering is on prices. Therefore you can always define a Comparator object and use this for the ordering:
public class CarPriceComparator extends Comparator<Car> {
#Override
public int compareTo(Car first, Car second) {
return Integer.compare(first.getPrice(), second.getPrice());
}
}
And you can use it with Collections.sort(cars, new CarPriceComparator()).
If you like Lambda expressions and method references which came with Java 8 you can also define the equivalent Comparator with less code like seen here:
Collections.sort(cars, Comparator.comparingInt(Car::getPrice))
Hey Have you tried using comparator interface?
If you just have to sort always with price only try using comparable interface.
You can refer the following link for details :
Let me know if you need more details
https://www.javatpoint.com/difference-between-comparable-and-comparator
I want to sort a List of objects by a specified attribute of those objects and I want to choose which attribute should be used for sorting. Example:
class Car{
private String name;
private String colour;
public enum sortBy {NAME, COLOUR};
public String name(){
return name;
}
public String colour(){
return colour;
}
public static Car[] getSortedArray(Car[] carArray, sortBy sortType){
HashMap<Object, Car> carMap = new HashMap<Object, Car>();
Object[] sortArray = new Object[carArray.length];
Object value = null;
for(int i = 0; i < carArray.length; i++){
if(sortType == sortBy.NAME){
value = carArray[i].name();
}else if(sortType == sortBy.COLOUR){
value = carArray[i].colour();
}
carMap.put(value, carArray[i]);
sortArray[i] = value;
}
Arrays.sort(sortArray);
Car[] sortedArray = new Car[sortArray.length];
for(int i = 0; i < sortArray.length; i++){
sortedArray[i] = carMap.get(sortArray[i]);
}
return sortedArray;
}
}
//external:
Car[] cars = getSomeCars();
Car[] nameSortedCars = Car.getSortedArray(cars, Car.sortBy.NAME);
Car[] colourSortedCars = Car.getSortedArray(cars, Car.sortBy.COLOUR);
The idea is simple:
I put all values that i want to sort by into an array, and i create a map that maps these values back to their objects. After I sorted this array I take the objects mapped to these values and put them in the same order into a new array which is then sorted by these values. The values are just created with type Object so I can sort by multiple types (not just Strings as in the example).
This works fine unless you have two objects with the same attribute value, then only one object will be in the returned array, but two times.
Is there a better way to achieve this sorting?
It would be much simpler to use custom comparators:
To sort by name:
Arrays.sort(carArray, Comparator.comparing(Car::name));
To sort by colour:
Arrays.sort(carArray, Comparator.comparing(Car::colour));
So you could modify getSortedArray():
public static Car[] getSortedArray(Car[] carArray, Comparator<Car> comparator) {
Car[] sorted = carArray.clone()
Arrays.sort(sorted, comparator);
return sorted;
}
And call it like this:
Car[] sorted = getSortedArray(carArray, Comparator.comparing(Car::name));
Edit:
If you use a language version that does not support these features, you can create the comparators by explicitly creating a nested class that implements the Comparator interface.
This, for example, is a singleton Comparator that compares Car instances by name:
static enum ByName implements Comparator<Car> {
INSTANCE;
#Override
public int compare(Car c1, Car c2) {
return c1.name().compareTo(c2.name());
}
}
Then call:
Car[] sorted = getSortedArray(carArray, ByName.INSTANCE);
TL;DR: There's already a wheel for that.
I would say the easiest way to do this is to create a comparator:
final Comparator<Car> byName = Comparator.comparing(Car::name);
final Comparator<Car> byColour = Comparator.comparing(Car::colour);
Then just use the appropriate method on Arrays to sort by a comparator:
Arrays.sort(carArray, byName);
Now you want to do it with an enum? Just have the enum implements Comparator<Car>:
enum SortBy implements Comparator<Car> {
NAME(Comparator.comparing(Car::name)),
COLOUR(Comparator.comparing(Car::colour));
private final Comparator<Car> delegate;
private SortBy(Comparator<Car> delegate) {
this.delegate = delegate;
}
#Override
public int compare(final Car o1, final Car o2) {
return delegate.compare(o1, o2);
}
}
Want to sort by name then by colour? Easy:
final Comparator<Car> byName = SortBy.NAME.thenComparing(SortBy.COLOUR);
Want to sort by name in reverse order? Easy:
final Comparator<Car> byName = SortBy.NAME.reversed();
You're reinventing the wheel! Life will be much easier for you if you use the templated Collections API. To do this, you would work with List instead of arrays, define a Comparator to do your sorting, and then let the API do the work for you.
Comparator<Car> carComparator = new Comparator<Car>(){
public int sort(Car car1, Car car2){
//Sorting logic goes here.
}
}
List<Car> cars = getCars();
cars = Collections.sort(cars, carComparator); //the cars collection is now sorted.
If you wanted to sometimes sort by one attribute or another, you could make my variable carComparator into its own class and define which attributes to sort by in the constructor.
Hope that helps :)
Edit: As others have pointed out, this approach also works with arrays. But unless you have a good reason to be working with Arrays, working with Collections will generally be easier.
I think the solution would be more efficient if you passed a Comparator implementation to the Arrays.sort. Right now, you are looping n*2 from the looks of it, the hash map (O(1)) plus the Arrays.sort (which is another 0(n log n) or such). If you do the below, you could skip the 2 loops, and the map, you are using currently.
You can simply create a Comparator like (rough code):
class CarComparator implements Comparator<Car> {
enum compareType; //plus setter
public int compareTo(Car a, Car b) {
if(compareType == COLOUR) return a.colour.compareTo(b.colour);
if(compareType == NAME.....
}
}
, and then simply send the array of Cars to
Arrays.sort(cars, new CarComparator(COLOUR))
, or use more specialised comparator classes, one for each attribute, and a factory to render them, and of course don't create a new Comparator() for each sort if this is happening often. :-)
Overall, this approach should make your code more efficient.
}
i have a class Car representing name and IDs of cars:
public class Car {
String name;
int ID;
}
and another class representing races in which i need to sort the cars by their order in race:
public class Race {
private Set<Car> cars = new TreeSet<>();
private Map<Integer, Integer> races = new TreeMap<>();//key represents the order in race, value represents the ID of a car, so i need to sort cars by the keys in races
...
public Collection getSortedCars() { ??? }
}
-any ideas how to get sorted cars? thanks much
EDIT: Im sorry, i used very bad example with values, so heres it with identifiers, i hope you get what i need..
I would not do this with a SortedSet, even though a custom Comparator could be used. The reason is because the races could be modified and thus invalidate any structure inside the TreeSet making the behavior "unpredictable".
Instead, I would make getSortedCars first get a sequence (e.g. a List) from the Set, and then sort and return such a sequence.
The actual sorting is "trivial" with Collections.sort and a custom Comparator as this is really a "sort by" operation, for instance:
class CompareCarsByWins implements Comparator<Car> {
Map<Car,Integer> wins;
public CompareCarsByWins(Map<Car,Integer> wins) {
this.wins = wins;
}
public int compareTo (Car a, Car b) {
// Actual code should handle "not found" cars as appropriate
int winsA = wins.get(a);
int winsB = wins.get(b);
if (winsA == winsB) {
// Tie, uhm, let's .. choose by name
return a.getName().compareTo(b.getName());
} else {
// Sort most wins first
return winsB - winsA;
}
}
// ..
}
// Usage:
List<Car> results = new ArrayList<Car>(cars);
Collections.sort(results, new CompareCarsByWins(races));
If an object car has a property fuel, and I have a list of these objects cars: how can I best calculate the sum of this property getCarsFuel() of all objects in the list?
class CarStock {
List<Car> cars;
public int getCarsFuel() {
int result = 0;
for (Car car : cars) {
result += car.getFuel();
}
return result;
}
}
class Car {
int fuel;
}
Are there better ways, or can't it be done less "boilerplate".
I could image something like sum(List<T> list, String property) -> sum(cars, "fuel")
?
If you can use lambdaj, you can write something like:
import static ch.lambdaj.Lambda.*;
List<Car> cars = ...;
int result = sumFrom(cars).getFuel();
For some more examples of how to use lambdaj, see the Features page on the lambdaj wiki.
I have two questions. I have an object here that is of type ArrayList, and for this case let's call it "Car".
I have made 2 of them:
Car car1 = new Car();
Car car2 = new Car();
I have a function to add items to those Car objects:
car1.addPart("Front Wheels");
car1.addPart("Rear Wheels");
car1.addPart("Rear View Mirror");
car2.addPart("Rims");
car2.addPart("Steering Wheel");
car2.addPart("Bumper");
I need to have a function called sameContents() that I can call on car1:
car1.sameContents(car2);
which passes in an object of type ArrayList and checks it with car1 to see if they have the same contents and in the same order.
public boolean sameContents(Car c) {
ArrayList<String> other_car = c; // error: Type mismatch:
// cannot convert from Car to ArrayList<String>
for (String c : this.parts) {
System.out.println(c);
for(String oc : other_car) {
// stuff
}
}
}
I seem to be having all sorts of issues with this one. I can't get the other_car variable to be used in a foreach loop.
The second one that needs to be done is transferContents.
It's called like:
car1.transferContents(car2);
which transfers the items in car2 into car1 and then leaves car2 empty. I can't seem to get the ArrayList to work again in a foreach loop which is what I think I need.
public void transfer(Car c) {
// code for transfer method.
// this.parts is the arraylist of car parts
for (Car c: c) {
this.parts.add(c);
}
// not sure how to set car2 to empty...
}
Given some List<T> foo, foreach loops, e.g.:
for(T item : foo){
// body
}
are just a shorthand syntax for this idiom:
Iterator<T> iter = foo.iterator();
while(iter.hasNext()){
T item = iter.next();
// body
}
To check that there are more items in the list, you call iter.hasNext(), to retrieve the next item, you call iter.next().
Walking two lists can be done by keeping around 2 iterators, checking that both iterators have more elements, and then retrieving those elements. We can eliminate some boundary conditions on different length lists by realizing that different length lists cannot contain the same elements (since one list has more than the other).
From your description, it sounds like Car contains a property List<String> parts;, so we can formulate a solution as:
// different sizes, can't be equal
if(this.parts.size() != other.parts.size()){
return false;
}
// get iterators
Iterator<String> left = this.parts.iterator();
Iterator<String> right = other.parts.iterator();
// safe to only check `left` because the lists are the same size
while(left.hasNext()){
// check if left part is equal to the right part
if(!left.next().equals(right.next())){
// values are different, know at this
// point they're not equal
return false;
}
}
// at this point, have exactly the same values
// in the same order.
return true;
As for your transferContents method, you have the right idea, but you cannot iterate over the Car, you need to iterate over the List<String> parts. To remove individual parts, you can use remove() method, called like the add method, or to remove all elements, you can call clear()
Putting this together:
for (String part : c.parts) {
this.parts.add(part);
}
c.parts.clear();
You can rely on the java api to do all that you need.
The ArrayList equals method checks for order while comparing two lists.
You can use the removeAll() and addAll() methods to transfer contents.
public class Car {
private final List<String> parts = new ArrayList<String>();
public void addPart(String p) {
parts.add(p);
}
public boolean sameContents(Car c) {
return this.parts.equals(c.parts);
}
public void transfer(Car c) {
final List<String> temp = new ArrayList<String>(c.parts);
temp.removeAll(this.parts);
this.parts.addAll(temp);
c.parts.clear();
}
}
Your car should not be an array list, but have one. E.g. something like this:
class Car {
ArrayList<String> parts;
// ...
}
Then your sameContents method can simply call the lists's .equals() method to do the comparison:
public boolean sameParts(Car other) {
return this.parts.equals(other.parts);
}
Similarly, for transferring parts from another car, use the methods of the Lists to add the parts to your list, and then clear the other list.