如何对包含年份的月份列表进行排序
How to sort a list of months with years
我有一个包含年份的月份列表,例如:[12-2014,11-2012,5-2014,8-2012]
我必须对它们进行排序最近的在最上面(或最晚的日期在最上面) 例如。 [12-2014,5-2014,11-2012,8-2012]
。
有人知道如何在 Java
中有效地执行此操作吗?
编辑:
classYearMonth
不可用,我在Java 7
尝试使用 comparator 或 comparable 并通过拆分来检查月份。
使用自定义字符串比较器。
http://docs.oracle.com/javase/7/docs/api/java/util/Comparator.html
如果你愿意,我可以把代码写出来。
现在是一些 sudo 代码:
Arrays.sort(yearList, new Comparator<String>{
//get the year and month of o1 and o2 as ints
//if the years are different then return the difference of the years
//if the years are the same then return the difference of the months
}
尝试类似的东西(现已测试):
private final static DateTimeFormatter YEAR_MONTH_FORMATTER =
DateTimeFormatter.ofPattern("M-yyyy");
...
List<String> yearMonthStrings = ...;
List<YearMonth> yearMonthList = yearMonthStrings.stream()
.map(s -> YearMonth.parse(s, YEAR_MONTH_FORMATTER))
.sorted()
.collect(Collectors.toList());
// or
List<YearMonth> yearMonthList = yearMonthStrings.stream()
.map(s -> YearMonth.parse(s, YEAR_MONTH_FORMATTER))
.sorted(Collections.reverseOrder())
.collect(Collectors.toList());
后者给出[2014-12, 2014-05, 2012-11, 2012-08]
.
由于您使用的是 Java 7,因此您可以利用 Date class 以及 Comparator 接口及其在 Set 对象(例如 treeSet)中的用法。
这里是 Comparator 接口的一个实现,用于比较两个日期
public class MonthYearComparator implements Comparator<Date> {
public int compare(Date o1, Date o2) {
// TODO Auto-generated method stub
return -1*o1.compareTo(o2);
}
}
下面是我们如何使用它。首先,我将使用 SimpleDateFormat class 将字符串解析为日期。为此,我需要完成它们并使它们看起来像格式化的日期字符串。由于日期与比较无关,所以我可以选择任何一天,例如“01”。
一旦我将它们转换为 Date 对象,我会将它们添加到随 Comparator 提供的 TreeSet 实例中,并且在我添加它们时它们会自动排序。
然后我可以减去我需要的日期部分,在格式化为字符串后,这将是我的日期对象的子字符串(3)。
这是代码(为了演示,我使用了您提供的相同数据作为示例):
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
public class MonthYearIssue {
private List<String> listOfMonthYears = new ArrayList<String>();
private static final String USED_DATE_FORMAT = "dd-MM-yyyy";
SimpleDateFormat formatter = new SimpleDateFormat(USED_DATE_FORMAT);
public void setUpMonthYearsList() {
listOfMonthYears.add("12-2014");
listOfMonthYears.add("11-2012");
listOfMonthYears.add("5-2014");
listOfMonthYears.add("8-2012");
}
public Date parseToDate(String monthYearString) throws ParseException {
return formatter.parse("01-" + monthYearString);
}
public List<String> doSort() throws ParseException {
List<String> result = new ArrayList<String>();
Set<Date> dates = new TreeSet<Date>(new MonthYearComparator());
for (String monthYearStr: listOfMonthYears) {
dates.add(parseToDate(monthYearStr));
}
for (Object d: dates.toArray()) {
result.add(formatter.format((Date)d).substring(3));
}
System.out.println(result);
return result;
}
public static void main(String[] args) throws ParseException {
MonthYearIssue issueSolver = new MonthYearIssue();
issueSolver.setUpMonthYearsList();
issueSolver.doSort();
}
}
结果如下:
[12-2014, 05-2014, 11-2012, 08-2012]
class日期具有可比性,因此您可以为数组中的每个字符串创建一个日期实例,然后对它们进行排序
Java-8以后
从列表中创建一个 Stream
,使用 DateTimeFormatter
将 Stream
中的每个 String
映射到 YearMonth
,对 [=12] 进行排序=] 使用 Comparator#reverseOrder
,使用相同的 DateTimeFormatter
将 Stream 的每个 YearMonth
元素映射到 String
,最后,将 Stream
收集到 [=23] =].
演示:
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
public class Main {
public static void main(String args[]) {
List<String> list = List.of("12-2014", "11-2012", "5-2014", "8-2012");
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("M-uuuu", Locale.ENGLISH);
List<String> sorted =
list.stream()
.map(s -> YearMonth.parse(s, dtf))
.sorted(Comparator.reverseOrder())
.map(ym -> dtf.format(ym))
.collect(Collectors.toList());
// Display the list
System.out.println(sorted);
}
}
输出:
[12-2014, 5-2014, 11-2012, 8-2012]
了解有关 modern Date-Time API* from Trail: Date Time 的更多信息。
* 如果您正在为 Android 项目工作,并且您的 Android API 级别仍然不符合 Java-8,请检查Java 8+ APIs available through desugaring. Note that Android 8.0 Oreo already provides support for java.time
。
tl;博士
永远不要使用糟糕的遗留日期时间 类,例如 Date
& Calendar
。
始终使用它们的替代品,即 JSR 310 中定义的现代 java.time 类。大部分功能已向后移植到 Java ThreeTen-Backport.
中的 6 和 7
List < String > inputs = Arrays.asList( "12-2014" , "11-2012" , "5-2014" , "8-2012" );
DateTimeFormatter f = DateTimeFormatter.ofPattern( "M-uuuu" );
List < YearMonth > yearMonths = new ArrayList <>( inputs.size() );
for ( String input : inputs )
{
try { yearMonths.add( YearMonth.parse( input , f ) ); } catch ( DateTimeException e ) { System.out.println( "ERROR - Faulty input: " + input ); }
}
Collections.sort( yearMonths , Collections.reverseOrder() );
后端口 java.time 到 Java 7
您说过您只能使用 Java 7. 尽管不是内置的,但您可以使用大多数现代 java.time 功能。将 ThreeTen-Backport 库添加到您的项目中。
如果使用 Maven,请将其添加到您的 POM 中:
<dependency>
<groupId>org.threeten</groupId>
<artifactId>threetenbp</artifactId>
<version>1.5.1</version>
</dependency>
遗留日期时间 类,例如 Date
、Calendar
、SimpleDateFormat
在设计上存在严重缺陷。它们真的是一团糟,以至于向您的项目添加一个库是值得的。
DateTimeFormatter
设置您的输入。
顺便说一下,您的输入文本使用的是自定义格式 M-YYYY。我建议您向数据发布者介绍 ISO 8601 格式化文本交换日期时间值的标准。年-月的标准格式是 YYYY-MM。
定义格式化程序以匹配您的非标准输入。
List < String > inputs = Arrays.asList( "12-2014" , "11-2012" , "5-2014" , "8-2012" );
DateTimeFormatter f = DateTimeFormatter.ofPattern( "M-uuuu" );
YearMonth
解析您输入的 YearMonth
个对象,为每个对象添加一个新的 List
。
如果输入可能有问题,您可以捕获 DateTimeException
来检测和处理此类问题。
List < YearMonth > yearMonths = new ArrayList <>( inputs.size() );
for ( String input : inputs )
{
try { yearMonths.add( YearMonth.parse( input , f ) ); } catch ( DateTimeException e ) { System.out.println( "ERROR - Faulty input: " + input ); }
}
Collections.sort
&& Collections.reverseOrder
对列表进行排序。你想要最新的第一个,所以传递可选的第二个参数,a Comparator
来反转自然顺序的排序。
Collections.sort( yearMonths , Collections.reverseOrder() );
报告我们的新列表。
System.out.println( "yearMonths = " + yearMonths );
示例代码
将所有代码放在一起。
package work.basil;
import org.threeten.bp.DateTimeException;
import org.threeten.bp.YearMonth;
import org.threeten.bp.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Example parsing year-month values using ThreeTen-Backport library
* giving us most of the Java 8+ *java.time* functionality.
**/
public class App
{
public static void main ( String[] args )
{
List < String > inputs = Arrays.asList( "12-2014" , "11-2012" , "5-2014" , "8-2012" );
DateTimeFormatter f = DateTimeFormatter.ofPattern( "M-uuuu" );
List < YearMonth > yearMonths = new ArrayList <>( inputs.size() );
for ( String input : inputs )
{
try { yearMonths.add( YearMonth.parse( input , f ) ); } catch ( DateTimeException e ) { System.out.println( "ERROR - Faulty input: " + input ); }
}
Collections.sort( yearMonths , Collections.reverseOrder() );
System.out.println( "yearMonths = " + yearMonths );
}
}
当运行.
yearMonths = [2014-12, 2014-05, 2012-11, 2012-08]
顺便说一下,这里是这个应用程序的 Maven POM,使用了各个部分的最新版本。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns = "http://maven.apache.org/POM/4.0.0"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>work.basil</groupId>
<artifactId>J7</artifactId>
<version>1.0-SNAPSHOT</version>
<name>J7</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!--https://www.threeten.org/threetenbp/-->
<dependency>
<groupId>org.threeten</groupId>
<artifactId>threetenbp</artifactId>
<version>1.5.1</version>
</dependency>
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.2.0</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>3.0.0-M1</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>3.0.0-M1</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.9.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.1.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
我有一个包含年份的月份列表,例如:[12-2014,11-2012,5-2014,8-2012]
我必须对它们进行排序最近的在最上面(或最晚的日期在最上面) 例如。 [12-2014,5-2014,11-2012,8-2012]
。
有人知道如何在 Java
中有效地执行此操作吗?
编辑:
classYearMonth
不可用,我在Java 7
尝试使用 comparator 或 comparable 并通过拆分来检查月份。
使用自定义字符串比较器。 http://docs.oracle.com/javase/7/docs/api/java/util/Comparator.html
如果你愿意,我可以把代码写出来。
现在是一些 sudo 代码:
Arrays.sort(yearList, new Comparator<String>{
//get the year and month of o1 and o2 as ints
//if the years are different then return the difference of the years
//if the years are the same then return the difference of the months
}
尝试类似的东西(现已测试):
private final static DateTimeFormatter YEAR_MONTH_FORMATTER =
DateTimeFormatter.ofPattern("M-yyyy");
...
List<String> yearMonthStrings = ...;
List<YearMonth> yearMonthList = yearMonthStrings.stream()
.map(s -> YearMonth.parse(s, YEAR_MONTH_FORMATTER))
.sorted()
.collect(Collectors.toList());
// or
List<YearMonth> yearMonthList = yearMonthStrings.stream()
.map(s -> YearMonth.parse(s, YEAR_MONTH_FORMATTER))
.sorted(Collections.reverseOrder())
.collect(Collectors.toList());
后者给出[2014-12, 2014-05, 2012-11, 2012-08]
.
由于您使用的是 Java 7,因此您可以利用 Date class 以及 Comparator 接口及其在 Set 对象(例如 treeSet)中的用法。
这里是 Comparator 接口的一个实现,用于比较两个日期
public class MonthYearComparator implements Comparator<Date> {
public int compare(Date o1, Date o2) {
// TODO Auto-generated method stub
return -1*o1.compareTo(o2);
}
}
下面是我们如何使用它。首先,我将使用 SimpleDateFormat class 将字符串解析为日期。为此,我需要完成它们并使它们看起来像格式化的日期字符串。由于日期与比较无关,所以我可以选择任何一天,例如“01”。
一旦我将它们转换为 Date 对象,我会将它们添加到随 Comparator 提供的 TreeSet 实例中,并且在我添加它们时它们会自动排序。
然后我可以减去我需要的日期部分,在格式化为字符串后,这将是我的日期对象的子字符串(3)。
这是代码(为了演示,我使用了您提供的相同数据作为示例):
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
public class MonthYearIssue {
private List<String> listOfMonthYears = new ArrayList<String>();
private static final String USED_DATE_FORMAT = "dd-MM-yyyy";
SimpleDateFormat formatter = new SimpleDateFormat(USED_DATE_FORMAT);
public void setUpMonthYearsList() {
listOfMonthYears.add("12-2014");
listOfMonthYears.add("11-2012");
listOfMonthYears.add("5-2014");
listOfMonthYears.add("8-2012");
}
public Date parseToDate(String monthYearString) throws ParseException {
return formatter.parse("01-" + monthYearString);
}
public List<String> doSort() throws ParseException {
List<String> result = new ArrayList<String>();
Set<Date> dates = new TreeSet<Date>(new MonthYearComparator());
for (String monthYearStr: listOfMonthYears) {
dates.add(parseToDate(monthYearStr));
}
for (Object d: dates.toArray()) {
result.add(formatter.format((Date)d).substring(3));
}
System.out.println(result);
return result;
}
public static void main(String[] args) throws ParseException {
MonthYearIssue issueSolver = new MonthYearIssue();
issueSolver.setUpMonthYearsList();
issueSolver.doSort();
}
}
结果如下:
[12-2014, 05-2014, 11-2012, 08-2012]
class日期具有可比性,因此您可以为数组中的每个字符串创建一个日期实例,然后对它们进行排序
Java-8以后
从列表中创建一个 Stream
,使用 DateTimeFormatter
将 Stream
中的每个 String
映射到 YearMonth
,对 [=12] 进行排序=] 使用 Comparator#reverseOrder
,使用相同的 DateTimeFormatter
将 Stream 的每个 YearMonth
元素映射到 String
,最后,将 Stream
收集到 [=23] =].
演示:
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
public class Main {
public static void main(String args[]) {
List<String> list = List.of("12-2014", "11-2012", "5-2014", "8-2012");
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("M-uuuu", Locale.ENGLISH);
List<String> sorted =
list.stream()
.map(s -> YearMonth.parse(s, dtf))
.sorted(Comparator.reverseOrder())
.map(ym -> dtf.format(ym))
.collect(Collectors.toList());
// Display the list
System.out.println(sorted);
}
}
输出:
[12-2014, 5-2014, 11-2012, 8-2012]
了解有关 modern Date-Time API* from Trail: Date Time 的更多信息。
* 如果您正在为 Android 项目工作,并且您的 Android API 级别仍然不符合 Java-8,请检查Java 8+ APIs available through desugaring. Note that Android 8.0 Oreo already provides support for java.time
。
tl;博士
永远不要使用糟糕的遗留日期时间 类,例如 Date
& Calendar
。
始终使用它们的替代品,即 JSR 310 中定义的现代 java.time 类。大部分功能已向后移植到 Java ThreeTen-Backport.
中的 6 和 7List < String > inputs = Arrays.asList( "12-2014" , "11-2012" , "5-2014" , "8-2012" );
DateTimeFormatter f = DateTimeFormatter.ofPattern( "M-uuuu" );
List < YearMonth > yearMonths = new ArrayList <>( inputs.size() );
for ( String input : inputs )
{
try { yearMonths.add( YearMonth.parse( input , f ) ); } catch ( DateTimeException e ) { System.out.println( "ERROR - Faulty input: " + input ); }
}
Collections.sort( yearMonths , Collections.reverseOrder() );
后端口 java.time 到 Java 7
您说过您只能使用 Java 7. 尽管不是内置的,但您可以使用大多数现代 java.time 功能。将 ThreeTen-Backport 库添加到您的项目中。
如果使用 Maven,请将其添加到您的 POM 中:
<dependency>
<groupId>org.threeten</groupId>
<artifactId>threetenbp</artifactId>
<version>1.5.1</version>
</dependency>
遗留日期时间 类,例如 Date
、Calendar
、SimpleDateFormat
在设计上存在严重缺陷。它们真的是一团糟,以至于向您的项目添加一个库是值得的。
DateTimeFormatter
设置您的输入。
顺便说一下,您的输入文本使用的是自定义格式 M-YYYY。我建议您向数据发布者介绍 ISO 8601 格式化文本交换日期时间值的标准。年-月的标准格式是 YYYY-MM。
定义格式化程序以匹配您的非标准输入。
List < String > inputs = Arrays.asList( "12-2014" , "11-2012" , "5-2014" , "8-2012" );
DateTimeFormatter f = DateTimeFormatter.ofPattern( "M-uuuu" );
YearMonth
解析您输入的 YearMonth
个对象,为每个对象添加一个新的 List
。
如果输入可能有问题,您可以捕获 DateTimeException
来检测和处理此类问题。
List < YearMonth > yearMonths = new ArrayList <>( inputs.size() );
for ( String input : inputs )
{
try { yearMonths.add( YearMonth.parse( input , f ) ); } catch ( DateTimeException e ) { System.out.println( "ERROR - Faulty input: " + input ); }
}
Collections.sort
&& Collections.reverseOrder
对列表进行排序。你想要最新的第一个,所以传递可选的第二个参数,a Comparator
来反转自然顺序的排序。
Collections.sort( yearMonths , Collections.reverseOrder() );
报告我们的新列表。
System.out.println( "yearMonths = " + yearMonths );
示例代码
将所有代码放在一起。
package work.basil;
import org.threeten.bp.DateTimeException;
import org.threeten.bp.YearMonth;
import org.threeten.bp.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Example parsing year-month values using ThreeTen-Backport library
* giving us most of the Java 8+ *java.time* functionality.
**/
public class App
{
public static void main ( String[] args )
{
List < String > inputs = Arrays.asList( "12-2014" , "11-2012" , "5-2014" , "8-2012" );
DateTimeFormatter f = DateTimeFormatter.ofPattern( "M-uuuu" );
List < YearMonth > yearMonths = new ArrayList <>( inputs.size() );
for ( String input : inputs )
{
try { yearMonths.add( YearMonth.parse( input , f ) ); } catch ( DateTimeException e ) { System.out.println( "ERROR - Faulty input: " + input ); }
}
Collections.sort( yearMonths , Collections.reverseOrder() );
System.out.println( "yearMonths = " + yearMonths );
}
}
当运行.
yearMonths = [2014-12, 2014-05, 2012-11, 2012-08]
顺便说一下,这里是这个应用程序的 Maven POM,使用了各个部分的最新版本。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns = "http://maven.apache.org/POM/4.0.0"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>work.basil</groupId>
<artifactId>J7</artifactId>
<version>1.0-SNAPSHOT</version>
<name>J7</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!--https://www.threeten.org/threetenbp/-->
<dependency>
<groupId>org.threeten</groupId>
<artifactId>threetenbp</artifactId>
<version>1.5.1</version>
</dependency>
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.2.0</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>3.0.0-M1</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>3.0.0-M1</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.9.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.1.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>