排序月份(带字符串)算法

时间:2010-01-20 00:02:11

标签: language-agnostic string-comparison sorting

我有这个月数组:

["January", "March", "December" , "October" ]

我想让它按照这样排序:

["January", "March", "October", "December" ] 

我目前正在考虑“if / else”可怕的级联,但我想知道是否还有其他方法可以做到这一点。

不好的一点是我只需要用“string”(即不使用Date对象或类似的东西)来做这件事。

什么是好方法?

10 个答案:

答案 0 :(得分:11)

如果我有办法提供自定义排序顺序,我会创建一个定义正确顺序的列表:

correct = List("January", "February", "March", ...)

然后按照列表中的位置排序,例如:

toSort.sort(a, b) => compare(correct.index(a), correct.index(b))

答案 1 :(得分:9)

创建一个名为> index的表,然后根据表中的值对数组进行排序。

在C#arr.sort(myCompare),Java Collections.sort(arr, myCompare),Python arr.sort(myCompare),PHP usort($arr, 'myCompare'),C ++ sort(vec.begin(), vec.end(), myCompare)中,有几个示例可能很有用。

答案 2 :(得分:4)

拥有一个具有正确排序的数组,并根据它进行排序。

另一种解决方案(如果您的语言支持它)是具有从月份名称到数字(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

答案 3 :(得分:1)

从Java POV谈起,我将去皮条客(我经常这样做)google-collections(很快将被Guava取代):

Arrays.sort(myMonths, Ordering.explicit("Jan", "Feb", "Mar", ....));

......你已经完成了。

如果其他人已经做过,请不要自己写,可能更有效率,并且使用比您可能更好的API。

在一般情况下没有帮助,但以防任何Java民众都有同样的问题......

答案 4 :(得分:1)

同事,

我发现问题/业务问题持续超过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));
        }
    }

}

享受它,就像一个魅力。

答案 5 :(得分:0)

对于像月份这样的东西,我只需要对我需要的数组进行硬编码......

var correctOrdering = {
    english: ["January", "February", "March", ...],
    french: ["Janvier", "Février", "Mars", ...],
    russian: ["Январь", "февраль", "март"],
    ...
};

月份名称不会很快改变。

答案 6 :(得分:0)

创建映射:

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.")

答案 7 :(得分:0)

感谢所有人的建议,我想将你们所有人都认可。

以下是生成的代码:

// 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

答案 8 :(得分:0)

TL;博士

EnumSet.of( Month.JANUARY , Month.MARCH , Month.OCTOBER , Month.DECEMBER ).toString()

枚举

如果您的语言提供了与Java一样强大的enum功能,请定义十几个对象。请参阅Oracle Tutorial

java.time.Month

java.time类包含方便的Month枚举,为1月至12月的每个月定义一个对象。

它们编号为1-12,并按正确顺序定义,1月至12月。

在您的代码库中,使用此枚举的对象来替换纯粹整数的使用或使用月份名称字符串。使用Month对象可提供类型安全性,确保有效值,并使您的代码更具自我记录性。

在Java中,EnumSetEnumMap是针对枚举值优化的SetMap的实现。它们执行速度非常快,占用的内存很少。

EnumSet<Month> months = EnumSet.of( Month.JANUARY , Month.MARCH , Month.OCTOBER , Month.DECEMBER );

EnumSet以自然顺序迭代,即枚举常量的声明顺序。所以无需明确排序您的收藏。

该类包含getDisplayName方法,用于生成月份名称的本地化字符串。指定TextStyle表示您想要文本的长度或缩写。并为(a)用于翻译的人类语言指定Locale,以及(b)用于确定缩写,标点符号和大小写等问题的文化规范。

for( Month month : months ) {
    String output = month.getDisplayName( TextStyle.SHORT_STANDALONE , Locale.CANADA_FRENCH );  // Or Locale.US, Locale.ITALY, etc.
    System.out.println( output );
}

答案 9 :(得分:-1)

每月添加一个前缀:


Jan -> aJan
Feb -> bFeb
...

排序,然后删除前缀。