Home > Software engineering >  Sort List<Object> by current month to Last six months
Sort List<Object> by current month to Last six months

Time:05-12

I am having the following data in my list:

    List<FeatureAnalyzeDTOResult> list = new ArrayList<>();
    list.add(new FeatureAnalyzeDTOResult("october", 46));
    list.add(new FeatureAnalyzeDTOResult("april", 46));
    list.add(new FeatureAnalyzeDTOResult("march", 46));
    list.add(new FeatureAnalyzeDTOResult("november", 30));
    list.add(new FeatureAnalyzeDTOResult("may", 46));
    list.add(new FeatureAnalyzeDTOResult("january", 53));
    list.add(new FeatureAnalyzeDTOResult("december", 30));

What am I trying to do?
I am trying to sort this data in a sequence such that the data is sorted by month and the month should start from the current month and count the previous six months.
For example:
Currently, it is May, and the data should be sorted in the following order:

[MAY, APRIL, MARCH, FEBRUARY, JANUARY, DECEMBER]    

And if any month is missing, it should simply skip it and go for the next month and should complete the count.

What I have tried so far?

I have tried the following code to get the current month and the preceding six months:

        YearMonth thisMonth = YearMonth.now();
    String[] month = new String[6];
    for (int i = 0; i < 6; i  ) {
        YearMonth lastMonth = thisMonth.minusMonths(i);
        DateTimeFormatter monthYearFormatter = DateTimeFormatter.ofPattern("MMMM");
        month[i] = lastMonth.format(monthYearFormatter);
        month[i] = month[i].toUpperCase();
    }

    List<String> monthList = Arrays.asList(month);
    System.out.println(monthList);

I have also tried writing a Comparator but it is not working as expected. I am a bit confused with the logic to write the Comparator.

        Comparator<FeatureAnalyzeDTOResult> comp = (o1, o2)
            -> monthList.indexOf(o2.getMonth().toUpperCase()) - monthList.indexOf(o1.getMonth().toUpperCase());
    list.sort(comp);

It gives the output as follows:

     [Feature: december Count: 30 
         , Feature: january Count: 53 
         , Feature: march Count: 46 
         , Feature: april Count: 46 
         , Feature: may Count: 46 
         , Feature: october Count: 46 
         , Feature: november Count: 30]

Here is the FeatureAnalyzeDTOResult class for reference:

class FeatureAnalyzeDTOResult {

private String month;
private int count;

public FeatureAnalyzeDTOResult(String feature, int count) {
    this.month = feature;
    this.count = count;
}

  public FeatureAnalyzeDTOResult() {
}
public String getMonth() {
    return month;
}

public void setMonth(String feature) {
    this.month = feature;
}

public int getCount() {
    return count;
}

public void setCount(int count) {
    this.count = count;
}

@Override
public String toString() {
    StringBuilder string = new StringBuilder();
    string.append("Feature: ").append(getMonth()).append(" Count: ").append(getCount()).append(" \n");
    return string.toString();
}

CodePudding user response:

Assuming current month will get the integer 0 (or 11), then assign each month a consecutive int.

for example, May = 0, June = 1, .... january = 8...

then, sort your input array and from there, the problem is really easy

CodePudding user response:

Here an alternative approach:

  • Get a list of months from Month enum from the java.time API
  • Rotate the list using Collections.rotate and current month value
  • Reverse the list using Collections.reverse
  • Create a comparator to compare months based on the index of above list
  • Stream, sort and limit

Something like

import java.util.Collections;
import java.util.Comparator;

public static void main(String[] args) {
    List<FeatureAnalyzeDTOResult> list = new ArrayList<>();
    list.add(new FeatureAnalyzeDTOResult("october", 46));
    list.add(new FeatureAnalyzeDTOResult("april", 46));
    list.add(new FeatureAnalyzeDTOResult("march", 46));
    list.add(new FeatureAnalyzeDTOResult("november", 30));
    list.add(new FeatureAnalyzeDTOResult("may", 46));
    list.add(new FeatureAnalyzeDTOResult("january", 53));
    list.add(new FeatureAnalyzeDTOResult("december", 30));


    List<Month> months = new ArrayList<>(Arrays.asList(Month.values()));
    Collections.rotate(months, 12 - YearMonth.now().getMonthValue());
    Collections.reverse(months);

    Comparator<FeatureAnalyzeDTOResult> comp =
            Comparator.comparingInt(f -> months.indexOf(Month.valueOf(f.getMonth().toUpperCase())));

    list.stream().sorted(comp).limit(6).forEach(System.out::println);
}

CodePudding user response:

Here's how I would do it:

enum Month {
    JANUARY,
    FEBRUARY,
    MARCH,
    APRIL,
    MAY,
    JUNE,
    JULY,
    AUGUST,
    SEPTEMBER,
    OCTOBER,
    NOVEMBER,
    DECEMBER
}
public static void main(String[] args) {
    List<String> data = Arrays.asList("october", "april", "march", "november", "may", "january", "december");
    Month currentMonth = Month.MAY;
    List<String> thisYear = data.stream()
                                .filter(a -> Month.valueOf(a.toUpperCase()).ordinal() <= currentMonth.ordinal())
                                .collect(Collectors.toList());
    List<String> lastYear = data.stream()
                                .filter(a -> Month.valueOf(a.toUpperCase()).ordinal() > currentMonth.ordinal())
                                .collect(Collectors.toList());
    Comparator<String> monthComparator = new Comparator<String>() {

        @Override
        public int compare(String a, String b) {    
            Month mA = Month.valueOf(a.toUpperCase());
            Month mB = Month.valueOf(b.toUpperCase());
            return mB.compareTo(mA);
        }
    };
    thisYear.sort(monthComparator);
    lastYear.sort(monthComparator);
    
    thisYear.addAll(lastYear);
    System.out.println(thisYear);
}

CodePudding user response:

You're nearly there. What you're missing are 2 things:

  1. You forgot to filter out months that are more than 6 months ago.
  2. You got the comparison reversed (so you're seeing things in ascending instead of descending order).

The following does both filtering and sorting:

    Comparator<FeatureAnalyzeDTOResult> comp =
            Comparator.comparingInt(o -> monthList.indexOf(o.getMonth().toUpperCase()));
    list = list.stream()
            .filter(o -> monthList.contains(o.getMonth().toUpperCase()))
            .sorted(comp)
            .toList();
    System.out.println(list);

Output:

[Feature: may Count: 46 
, Feature: april Count: 46 
, Feature: march Count: 46 
, Feature: january Count: 53 
, Feature: december Count: 30 
]
  • Related