Сортировка списка объектов на основе вложенных значений в Java - PullRequest
3 голосов
/ 10 октября 2019

У меня есть список автомобилей, запланированных к отправке на несколько дат, которые необходимо отсортировать на основе следующих пунктов:

  • Если isReady>0,, то следуетбудет отображаться первым в таблице. А затем другие значения идут под ним на эту конкретную дату.
  • Если isReady>0 и Object gear!=null, то он отображается первым в таблице для этой конкретной даты. Далее следуют другие значения, где Object gear==null.
  • Если isReady>0, Объект gear!=null и Объект tyre!=null, то это значение отображается первым в таблице для этой конкретной даты. Вслед за другими значениями, где Object gear==null и tyre==null.

Вот коды class:

public class Car {
    private int isReady;
    private Tyre tyre;
    private Gear gear;
    private Date deliveryDate;
}


public class Gear {
    private int id;
    private String type;
}


public class Tyre {
    private int id;
    private String grip;
}

public class CarComparator implements Comparator<Car> {
    @Override
    public int compare(Car entry1, Car entry2) {
        int value = 0;

        if (entry1.getIsReady() > entry2.getIsReady()) {
            value = -1;
        } else if (entry1.getIsReady() < entry2.getIsReady()) {
            value = 1;
        } else if (entry1.getIsReady() == entry2.getIsReady()) {
            value = 0;
        }
        return value;
    }
}

Я разработал Компаратор, которыйотлично работает для первого условия, где isReady>0. Не могли бы вы помочь мне с другими условиями, упомянутыми выше.

Заранее спасибо.

Ответы [ 4 ]

2 голосов
/ 10 октября 2019

Что касается Java 8, вы можете создать свой компаратор следующим образом:

//order by delivery date first, ascending order
Comparator<Car> carComparator = Comparator.comparing( Car::getDeliveryDate )
  //order by isReady in ascending order
  .thenComparing( Car::getIsReady )
  //we map null to 1 and non-null to -1 and ignore the rest for now
  .thenComparing( car -> car.getGear() != null ? -1 : 1 ) 
  .thenComparing( car -> car.getTyre() != null ? -1 : 1 );
2 голосов
/ 10 октября 2019

Проверьте этот компаратор, чтобы вы могли сортировать по нескольким атрибутам

public class CarComparator implements Comparator<Car> {

    @Override
    public int compare(Car entry1, Car entry2) {
        int value;
        if (entry1.getDeliveryDate().before(entry2.getDeliveryDate())){
            value = -1;
        }else if (entry1.getDeliveryDate().equals(entry2.getDeliveryDate())){
            value = 0;
        }else{
            value =1;
        }
        //For same day
        if (value==0){
            if (entry1.getIsReady() > entry2.getIsReady()) {
                value = -1;
            } else if (entry1.getIsReady() < entry2.getIsReady()) {
                value = 1;
            } else if (entry1.getIsReady() == entry2.getIsReady()) {
                value = 0;
            }
        }
        //if same isReady
        if (value==0){
            if (entry1.getGear()!=null && entry2.getGear()==null) {
                value = -1;
            } else  if (entry1.getGear()==null && entry2.getGear()==null) {
                value = 0;
            } else{
                value = 1;
            }
        }
        //if still equals
        if (value==0){
            if (entry1.getTyre()!=null && entry2.getTyre()==null) {
                value = -1;
            } else  if (entry1.getTyre()==null && entry2.getTyre()==null) {
                value = 0;
            } else{
                value = 1;
            }
        }


        return value;
    }
}

Я не уверен, что вы пытаетесь это сделать. То, что делает вышеупомянутый компаратор: сначала сортирует по датам, если он находит одинаковые даты (значение = 0), он сравнивает isReady, затем getGear () и, наконец, getTyre ().

Таким образом, вы можетедобавьте в свой компаратор столько атрибутов, сколько вам нужно.

Включая метод main с 3 машинами

public class Main {
    public static void main (String[]args) throws UnsupportedEncodingException, ParseException {

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

        Car car1 = new Car();
        car1.setDeliveryDate(new Date());
        Gear gear1 = new Gear();
        car1.setGear(gear1);
        Tyre tyre1 = new Tyre();
        car1.setTyre(null);
        car1.setId(1);
        car1.setDeliveryDate((new SimpleDateFormat("dd-MM-yyyy")).parse("01-01-2000"));
        car1.setIsReady(0);

        Car car2 = new Car();
        car2.setDeliveryDate(new Date());
        Gear gear2 = new Gear();
        car2.setGear(gear2);
        Tyre tyre2 = new Tyre();
        car2.setTyre(tyre2);
        car2.setId(2);
        car2.setDeliveryDate((new SimpleDateFormat("dd-MM-yyyy")).parse("02-01-2000"));

        car2.setIsReady(1);

        Car car3 = new Car();
        car3.setDeliveryDate(new Date());
        Gear gear3 = new Gear();
        car3.setGear(gear3);
        Tyre tyre3 = new Tyre();
        car3.setTyre(tyre3);
        car3.setId(3);
        car3.setDeliveryDate((new SimpleDateFormat("dd-MM-yyyy")).parse("01-01-2000"));

        car3.setIsReady(1);

        carL.add(car1);
        carL.add(car2);
        carL.add(car3);
        Collections.sort(carL, new CarComparator());
        for (Car car : carL) {
            System.out.println("car: " + car.toString());
        }
    }
}

Вывод:

car: Car{id=3, isReady=1, tyre=false, gear=false, deliveryDate=Sat Jan 01 00:00:00 EET 2000}
car: Car{id=1, isReady=0, tyre=true, gear=false, deliveryDate=Sat Jan 01 00:00:00 EET 2000}
car: Car{id=2, isReady=1, tyre=false, gear=false, deliveryDate=Sun Jan 02 00:00:00 EET 2000}
0 голосов
/ 10 октября 2019

почему бы не использовать Integer.compareTo, чтобы сделать код короче?

примерно так:

import java.util.Comparator;

public class CarComparator implements Comparator<Car> {
    @Override
    public int compare(Car entry1, Car entry2) {
        int value = 0;

        // might want to add a null check for either entry1 and entry2

        value = entry1.getDeliveryDate().compareTo(entry2.getDeliveryDate());
        if (value == 0) {
            value = ((Integer)entry1.getIsReady()).compareTo((Integer)entry2.getIsReady());
            if (value == 0) {
                value = getIntegerValueForNullCheck(entry1.getGear()).compareTo(getIntegerValueForNullCheck(entry2.getGear()));
                if (value == 0) {
                    value = getIntegerValueForNullCheck(entry1.getTyre()).compareTo(getIntegerValueForNullCheck(entry2.getTyre()));
                }
            }
        }

        return value;
    }
    private Integer getIntegerValueForNullCheck (Object o) {
        return o == null ? 0 : 1;
    }
}

включая код, который проверяет сортировку:

import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.*;

public class Sorting {

    public static void main(String[] args) {

        List<Car> cars = new LinkedList<>();


        Date today = new Date();
        Instant now = Instant.now();
        Instant after = now.plus(Duration.ofDays(1));
        Date tomorrow = Date.from(after);

        cars.add(new Car(5, new Tyre(1,"1"), new Gear(1, "1"), today ));
        cars.add(new Car(5, new Tyre(1,"1"), null, today ));
        cars.add(new Car(5, null, null, today ));
        cars.add(new Car(4, null, null, today ));
        cars.add(new Car(3, null, null, tomorrow ));


        Collections.sort(cars, new CarComparator());
        System.out.println(cars);
    }

}

вывод:

[Car{isReady=4, tyre=null, gear=null, deliveryDate=Thu Oct 10 11:27:20 IDT 2019}
, Car{isReady=5, tyre=null, gear=null, deliveryDate=Thu Oct 10 11:27:20 IDT 2019}
, Car{isReady=5, tyre=Tyre{id=1, grip='1'}, gear=null, deliveryDate=Thu Oct 10 11:27:20 IDT 2019}
, Car{isReady=5, tyre=Tyre{id=1, grip='1'}, gear=Gear{id=1, type='1'}, deliveryDate=Thu Oct 10 11:27:20 IDT 2019}
, Car{isReady=3, tyre=null, gear=null, deliveryDate=Fri Oct 11 11:27:20 IDT 2019}
]
0 голосов
/ 10 октября 2019

Если честно, я не вижу ничего плохого в вашем коде. То есть, если вы намереваетесь вернуть -1, когда entry1 больше, чем запись 2 (обратный порядок нормы). Без дополнительного кода для чтения, я думаю, что ваш код будет работать, если вы пытаетесь сравнить, какое значение больше или меньше, которое построено для вашего случая использования.

Однако я думаю, что в вашем методе возврата есть некоторая неэффективность,Вам не нужно возвращать значение. Вы можете просто вернуть фактическое значение.

Для сравнения вы можете просто сравнить == сначала, а затем оценить остальные. Но это может быть трудно прочитать код, поэтому я даю вам две версии.

Удалить версию значения:

public class CarComparator implements Comparator<Car> {
    @Override
    public int compare(Car entry1, Car entry2) {
        if (entry1.getisReady() > entry2.getisReady()) {
            return -1;
        } else if (entry1.getisReady() < entry2.getisReady()) {
            return 1;
        } else if (entry1.getisReady() == entry2.getisReady()) {
            return 0;
        }
    }
}

Удалить значение и другой стиль сравнения:

public class CarComparator implements Comparator<Car> {

    @Override
    public int compare(Car entry1, Car entry2) {
        if (entry1.getisReady() == entry2.getisReady()) return 0;            
        return entry1.getisReady() > entry2.getisReady()? -1 : 1;
    }
}

Я не уверен, правильно ли я вас понял, но если нет, надеюсь, этот код поможет вам. Я разделил их на 3 метода, и я надеюсь, что вы получили методы getTyre () и getGear (). Вы можете комбинировать их по мере необходимости, и для последнего метода его значения были разделены в порядке переменных для удобства чтения кода.

class CarComparator implements Comparator<Car> {

    public int compare(Car entry1, Car entry2) {
        if (entry1.getisReady() == entry2.getisReady()) return 0;
        return entry1.getisReady() > entry2.getisReady()? -1 : 1;
    }

    public int compareGear(Car entry1, Car entry2){
        if ( (entry1.getGear() != null && entry2.getGear() != null) 
           ||(entry1.getGear() == null && entry2.getGear() == null)
           ){
            return compare(entry1, entry2);
        }  
        return entry1.getGear() != null && entry2.getGear() == null? -1 : 1;

    }

    public int compareTye(Car entry1, Car entry2){
        int order1 = entry1.getGear() != null && entry1.getTyre() != null? 1 : 0;
        int order2 = entry2.getGear() != null && entry2.getTyre() != null? 1 : 0;

        if ( order1 == order2 ) return compare(entry1, entry2);
        return order1 > order2? -1 : 1;
    } 
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...