【问题标题】:How to sort an ArrayList of Strings with seasons and years?如何按季节和年份对字符串的 ArrayList 进行排序?
【发布时间】:2021-10-06 22:48:00
【问题描述】:

我有一个未排序的季节和年份字符串数组列表,如下所示:

["Summer 2020", "Autumn 2018", "Spring 2019", "Autumn 2019", "Winter 2018", "Summer 2018", "Winter 2020", "Spring 2018"]

这个列表的正确排序如下:

["Winter 2018", "Spring 2018", "Summer 2018", "Autumn 2018", "Spring 2019", "Autumn 2019", "Winter 2020", "Summer 2020"]

我怎样才能实现这个订单?一年中的季节顺序为 2021 年冬季、2021 年春季、2021 年夏季、2021 年秋季,并且每年的所有季节都不一定存在于列表中。

【问题讨论】:

  • 问:如何像这样对包含季节和年份的 ArrayList 进行排序? A:看起来你的例子甚至不是合法的Java。我猜你的 ArrayList 实际上由“字符串”元素组成。在任何情况下:1) 只需编写自定义Comparator。 2) 您的比较器将解析您正在比较的“季节”和“年份”的两个元素,然后根据需要返回 -1、0 或 1。十分简单。查看我引用的示例链接。
  • 我会添加 ThreeTen-Extra 以使用其 YearQuarter 类而不是字符串。

标签: java list sorting arraylist


【解决方案1】:

您需要实现一个自定义Comparator,先按年份排序,然后按季节排序。 enum 可用于轻松指定季节的顺序。

private static class SeasonComparator implements Comparator<String> {
    
    private enum Season {
        WINTER, SPRING, SUMMER, AUTUMN
    }

    @Override
    public int compare(String s1, String s2) {
        String[] arr1 = s1.split(" ");
        String[] arr2 = s2.split(" ");
        
        int year1 = Integer.parseInt(arr1[1]);
        int year2 = Integer.parseInt(arr2[1]);
        
        if (year1 != year2) {
            return year1 - year2;
        } else {
            Season season1 = Season.valueOf(arr1[0].toUpperCase());
            Season season2 = Season.valueOf(arr2[0].toUpperCase());
            return season1.ordinal() - season2.ordinal();
        }
    }
}

public static void main(String[] args) {
    List<String> seasons = new ArrayList<>(Arrays.asList("Summer 2020", "Autumn 2018",
            "Spring 2019", "Autumn 2019", "Winter 2018", "Summer 2018", "Winter 2020", "Spring 2018"));

    System.out.println("Unordered list:");
    System.out.println(seasons);
    
    seasons.sort(new SeasonComparator());
    
    System.out.println("Sorted list:");
    System.out.println(seasons);
}

输出

Unordered list:
[Summer 2020, Autumn 2018, Spring 2019, Autumn 2019, Winter 2018, Summer 2018, Winter 2020, Spring 2018]

Sorted list:
[Winter 2018, Spring 2018, Summer 2018, Autumn 2018, Spring 2019, Autumn 2019, Winter 2020, Summer 2020]

【讨论】:

    【解决方案2】:

    您需要为此类字符串编写自己的comparator。我建议你使用arrow 函数。另外,要对季节进行排序,您需要给它们一些优先级,我会使用Map&lt;String, Integer&gt;。

    试试这个代码:

    public static void main(String[] args) {
        Map<String, Integer> seasonsPriority = new HashMap<>();
        seasonsPriority.put("Winter", 1);
        seasonsPriority.put("Spring", 2);
        seasonsPriority.put("Summer", 3);
        seasonsPriority.put("Autumn", 4);
    
        ArrayList<String> seasons = new ArrayList<>();
        seasons.add("Summer 2020");
        seasons.add("Autumn 2018");
        seasons.add("Spring 2019");
        seasons.add("Autumn 2019");
        seasons.add("Winter 2018");
        seasons.add("Summer 2018");
        seasons.add("Winter 2020");
        seasons.add("Spring 2018");
    
    
        seasons.sort((x, y) -> {
            int firstYear = Integer.parseInt(x.split(" ")[1]);
            int secondYear = Integer.parseInt(y.split(" ")[1]);
    
            if(firstYear < secondYear) {
                return -1;
            }
    
            if(firstYear > secondYear) {
                return 1;
            }
    
            String firstSeason = x.split(" ")[0];
            String secondSeason = y.split(" ")[0];
    
            return Integer.compare(seasonsPriority.get(firstSeason), seasonsPriority.get(secondSeason));
        });
    
        System.out.println(seasons);
    }
    

    输出:

    [Winter 2018, Spring 2018, Summer 2018, Autumn 2018, Spring 2019, Autumn 2019, Winter 2020, Summer 2020]
    

    【讨论】:

      【解决方案3】:

      考虑编写一个自定义 Comparator 以使用自定义逻辑执行排序。

      public static void main(String[] args) {
          List<String> list = Arrays.asList("Summer 2020", "Autumn 2018", "Spring 2019", "Autumn 2019", "Winter 2018", "Summer 2018", "Winter 2020", "Spring 2018");
      
          List<String> listOfSeasonsInAscendingOrder = Arrays.asList("Winter", "Spring", "Summer", "Autumn");
      
          Collections.sort(list, new Comparator<String>() {
              @Override
              public int compare(String o1, String o2) {
                  String firstStringSplit[] = o1.split(" ");
                  String season1 = firstStringSplit[0];
                  int year1 = Integer.valueOf(firstStringSplit[1]);
      
                  String secondStringSplit[] = o2.split(" ");
                  String season2 = secondStringSplit[0];
                  int year2 = Integer.valueOf(secondStringSplit[1]);
      
                  if (year1 != year2) {
                      return year1 < year2 ? -1 : 1;
                  }
      
                  int indexOfSeason1 = listOfSeasonsInAscendingOrder.indexOf(season1);
                  int indexOfSeason2 = listOfSeasonsInAscendingOrder.indexOf(season2);
      
                  return indexOfSeason1 == indexOfSeason2 ? 0 : indexOfSeason1 < indexOfSeason2 ? -1 : 1;
              }
          });
      
          System.out.println("Sorted List = " + list);
      }
      

      以上代码的输出是:-

      Sorted List = [Winter 2018, Spring 2018, Summer 2018, Autumn 2018, Spring 2019, Autumn 2019, Winter 2020, Summer 2020]
      

      【讨论】:

        【解决方案4】:

        试试这个。

        static final Map<String, Integer> SEASON_ORDER = Map.of(
            "Winter", 0, "Spring", 1, "Summer", 2, "Autumn", 3);
        
        public static void main(String[] args) {
            List<String> list = new ArrayList<>(List.of(
                "Summer 2020", "Autumn 2018", "Spring 2019", "Autumn 2019",
                "Winter 2018", "Summer 2018", "Winter 2020", "Spring 2018"));
            list.sort(Comparator.comparing(s -> {
                String[] a = s.split("\\s+");
                return a[1] + SEASON_ORDER.get(a[0]);
            }));
            System.out.println(list);
        }
        

        输出:

        [Winter 2018, Spring 2018, Summer 2018, Autumn 2018, Spring 2019, Autumn 2019, Winter 2020, Summer 2020]
        

        【讨论】:

          【解决方案5】:

          前面的答案都是在比较器函数中执行字符串拆分和解析。这工作得很好,但可能会导致大规模的性能问题 - 拆分和解析可能是相对昂贵的操作,并且在对比较器进行排序时需要平均检查每个元素不止一次。让比较器为每个自然正确排序的元素计算一个代码,并使用映射记住这些代码,以避免每个元素多次执行这些操作,这可能会提高性能:

          public class Scratch {
              public static void main(String[] args) {
                  List<String> list = Arrays.asList("Summer 2020", "Autumn 2018", "Spring 2019", "Autumn 2019", "Winter 2018", "Summer 2018", "Winter 2020", "Spring 2018");
                  list.sort(new SeasonYearComparator());
                  System.out.println(list);
              }
          
              private enum Season {
                  Winter, Spring, Summer, Autumn;
              }
          
              private static class SeasonYearComparator implements Comparator<String> {
                  private final Map<String, String> codes = new HashMap<>();
          
                  @Override
                  public int compare(String s1, String s2) {
                      String code1 = codes.computeIfAbsent(s1, this::computeCode);
                      String code2 = codes.computeIfAbsent(s2, this::computeCode);
                      return code1.compareTo(code2);
                  }
          
                  private String computeCode(String seasonYear) {
                      String[] parts = seasonYear.split(" ");
                      return parts[1] + Season.valueOf(parts[0]).ordinal();
                  }
              }
          }
          

          【讨论】:

            猜你喜欢
            • 2018-10-01
            • 1970-01-01
            • 1970-01-01
            • 2011-11-26
            • 2023-01-01
            • 2012-07-12
            • 2012-12-24
            • 2016-03-11
            • 1970-01-01
            相关资源
            最近更新 更多