我有这个月份的数组:
["January", "March", "December" , "October" ]
我想让它像这样排序:
["January", "March", "October", "December" ]
我目前正在考虑“if/else”可怕的级联,但我想知道是否还有其他方法可以做到这一点。
不好的部分是我只需要使用“字符串”来执行此操作(即,不使用 Date 对象或类似的东西)
什么是好方法?
我有这个月份的数组:
["January", "March", "December" , "October" ]
我想让它像这样排序:
["January", "March", "October", "December" ]
我目前正在考虑“if/else”可怕的级联,但我想知道是否还有其他方法可以做到这一点。
不好的部分是我只需要使用“字符串”来执行此操作(即,不使用 Date 对象或类似的东西)
什么是好方法?
如果我有办法提供自定义排序顺序,我会创建一个定义正确顺序的列表:
correct = List("January", "February", "March", ...)
然后按该列表中的位置排序,例如:
toSort.sort(a, b) => compare(correct.index(a), correct.index(b))
使用名称->索引创建一个表,然后根据其在表中的值对数组进行排序。
arr.sort(myCompare)
在 C# 、 Java Collections.sort(arr, myCompare)
、 Python arr.sort(myCompare)
、 PHPusort($arr, 'myCompare')
和 C++中,有几个示例可能很有用sort(vec.begin(), vec.end(), myCompare)
。
有一个正确排序的数组,并根据它进行排序。
另一种解决方案(如果您的语言支持)是有一个从月份名称到数字(1..12)的关联数组,并使用自定义比较器在您的数组上运行排序。
Perl 中的解决方案:D
my @mon = qw( January February March April May June July August September October November December );
my $mon;
@{$mon}{@mon} = (0..$#mon);
sub by_month {
$mon->{$a} <=> $mon->{$b};
}
sort by_month @data_to_sort
(虽然我确信高尔夫球手可以在 < 30 个字符内做到这一点)
这是纯 C 语言的解决方案:http ://www.pnambic.com/CPS/SortAnal/html/MonOrder.html
从 Java POV 说起,我要拉皮条(就像我经常做的那样)google-collections(很快将被Guava取代):
Arrays.sort(myMonths, Ordering.explicit("Jan", "Feb", "Mar", ....));
...你就完成了。
如果其他人已经完成,请不要自己编写它,可能比您可能更有效且使用更好的 API。
在一般情况下没有帮助,但以防万一任何 Java 人有同样的问题......
同事,
我看到问题/业务问题持续超过 2 年。我决定编写比较器来正确排序月份的名称(存储为字符串)。它还包含所需语言环境的月份名称 ============== 比较器 =======================
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
/**
*
* @author akashtalyan
*/
public class MonthNamesComparator implements Comparator {
private static Map<Locale, List> monthMap = new HashMap<Locale, List>();
private final Locale locale;
public MonthNamesComparator(Locale locale) {
if (locale == null) {
throw new NullPointerException("MonthNamesComparator cannot accept null value for Locale parameter.");
}
List months = new ArrayList(12);
Calendar cal = Calendar.getInstance(locale);
SimpleDateFormat dateFormat = new SimpleDateFormat("MMMM", locale);
this.locale = locale;
if (!monthMap.containsKey(locale)) {
for (int i = 0; i < 12; i++) {
cal.set(Calendar.MONTH, i);
months.add(dateFormat.format(cal.getTime()).toLowerCase());
}
monthMap.put(locale , months);
}
}
@Override
public int compare(Object month1, Object month2) {
List months = monthMap.get(this.locale);
if (months == null) {
throw new NullPointerException("MonthNamesComparator cannot perform comparison - internal data is not initialized properly.");
}
return (months.indexOf(((String) month1).toLowerCase()) - months.indexOf(((String) month2).toLowerCase()));
}
}
POC 的简单测试类:
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
/**
*
* @author akashtalyan
*/
public class TestMonths {
public static void main(String[] args){
Locale en = Locale.ENGLISH, ru = new Locale("ru","RU");
String[] monthsToTestEn = new String[] {"FebRUary", "maY", "sepTember", "january", "december"};
String[] monthsToTestRu = new String[] {"АпреЛь", "январь", "Март", "Август"};
Map map = new TreeMap(new MonthNamesComparator(en));
int i = 0;
System.out.println("En Map original:");
for (String month : monthsToTestEn) {
System.out.print(month + " ");
map.put(month, new StringBuilder(String.valueOf(++i)).append(" position in source array").toString());
}
System.out.println();
System.out.println("En Map sorted:");
for (String month : (Set<String>)map.keySet()) {
System.out.println(month + " " + map.get(month));
}
i = 0;
map = new TreeMap(new MonthNamesComparator(ru));
System.out.println("Ru Map original:");
for (String month : monthsToTestRu) {
System.out.print(month + " ");
map.put(month, new StringBuilder(String.valueOf(++i)).append(" position in source array").toString());
}
System.out.println();
System.out.println("Ru Map sorted:");
for (String month : (Set<String>)map.keySet()) {
System.out.println(month + " " + map.get(month));
}
}
}
享受它,就像一个魅力。
几个月来,我只是对我需要的数组进行硬编码......
var correctOrdering = {
english: ["January", "February", "March", ...],
french: ["Janvier", "Février", "Mars", ...],
russian: ["Январь", "февраль", "март"],
...
};
月份名称不会很快改变。
创建映射:
month_map = {"January":1,
"February":2,
"March":3,
"April":4} # etc..
使用映射比较一个月与另一个月。
或者
大多数语言/框架都有处理日期的对象。为所有月份创建日期对象并使用本机(如果可用)不等式运算符或基本排序函数进行比较:
import datetime
January = datetime.date(2010,1,1)
February = datetime.date(2010,2,1)
if February < January: print("The world explodes.")
感谢大家的建议,我想将你们都标记为已接受。
这是生成的代码:
// correct order
months as String[] = ["jan", "feb", "mar", "apr", "may", "jun",
"jul", "aug", "sep", "oct", "nov", "dec"]
// my unsorted months
myMonths as String[] = ["mar", "dec", "jul", "jan", "sep"]
// poor substitute for Map
mappedIndex as Int[]
// create an array with the corresponding index
for each m in myMonths do
i as Int = 0;
for each month in months do
if m == month then
mappedIndex[] = i // no break, so I should use "else"
else
i = i + 1
end
end
end
// At this point mapped index has the same order as my "unsorted" array
// in this case [2,11,5,0,8]
// Fortunately this language has "sort" otherwise I would jump out of the window
mappedIndex.sort()
// create a new array to hold the sorted values
myMonthsSorted as String[]
// and fill it with the correct value
for each i in mappedIndex do
myMonthsSorted[] = months[i]
end
EnumSet.of( Month.JANUARY , Month.MARCH , Month.OCTOBER , Month.DECEMBER ).toString()
如果您的语言像 Java 一样提供强大的枚举功能,请定义十几个对象。请参阅Oracle 教程。
java.time.Month
java.time类包括方便的枚举,为每年 1 月至 12 月的每个月定义了十几个对象。Month
它们编号为 1-12,并按正确的顺序定义,即 1 月至 12 月。
在您的代码库中,使用此枚举的对象来替换任何仅使用整数或使用月份名称字符串的情况。在整个过程中使用Month
对象提供类型安全,确保有效值,并使您的代码更具自我记录性。
在 Java 中, and 是针对枚举值优化的and的EnumSet
实现EnumMap
。它们执行速度非常快,占用的内存很少。Set
Map
EnumSet<Month> months = EnumSet.of( Month.JANUARY , Month.MARCH , Month.OCTOBER , Month.DECEMBER );
The EnumSet
iterates in natural order, the order in which the enum constants are declared. So no need to explicitly sort your collection.
The class includes a getDisplayName
method for generating a localized String of the name of the month. Specify a TextStyle
for how long or abbreviated you want the text. And specify a Locale
for (a) the human language to use in translation, and (b) the cultural norms to decide issues such as abbreviation, punctuation, and capitalization.
for( Month month : months ) {
String output = month.getDisplayName( TextStyle.SHORT_STANDALONE , Locale.CANADA_FRENCH ); // Or Locale.US, Locale.ITALY, etc.
System.out.println( output );
}
为每个月添加一个前缀:
Jan -> aJan
Feb -> bFeb
...
排序,然后删除前缀。