Алгоритм сортировки месяцев (со строками) - PullRequest
6 голосов
/ 20 января 2010

У меня есть этот массив месяцев:

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

И я хочу, чтобы он был отсортирован так:

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

В настоящее время я думаю, что "если / еще" ужасноКаскад, но мне интересно, есть ли другой способ сделать это.

Плохая часть заключается в том, что мне нужно делать это только со строкой (то есть без использования объекта Date или чего-либо подобного)

Что было бы хорошим подходом?

Ответы [ 10 ]

11 голосов
/ 20 января 2010

Если бы у меня был способ предоставить пользовательский порядок сортировки, я бы создал список, определяющий правильный порядок:

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

А затем сортируйте по позиции в этом списке, что-то вроде:

toSort.sort(a, b) => compare(correct.index(a), correct.index(b))
9 голосов
/ 20 января 2010

Создайте таблицу с именем-> 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).

4 голосов
/ 20 января 2010

Иметь массив с правильной сортировкой и сортировать по нему.

Другое решение (если ваш язык поддерживает это) - это иметь ассоциативный массив из названий месяцев в числа (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 символов) </p>

А вот решение в простом C: http://www.pnambic.com/CPS/SortAnal/html/MonOrder.html

1 голос
/ 22 мая 2012

Коллеги,

Я вижу, проблема / бизнес-проблема длится более 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));
        }
    }

}

Наслаждайтесь этим, работает как шарм.

1 голос
/ 20 января 2010

Говоря от Java POV, я собираюсь сутенер (как я часто это делаю) google-collection (скоро будет заменен на Guava ):

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

... и все готово.

Не пишите это самостоятельно, если кто-то другой сделал это, возможно, более эффективно и с более приятным API, чем вы, вероятно, сделали бы.

В общем случае бесполезен, но на всякий случай у любого народа Java такая же проблема ...

0 голосов
/ 31 августа 2016

tl; dr

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

Enum

Если ваш язык предоставляет мощное средство enum , как и Java, определите дюжину объектов.См. Oracle Tutorial .

java.time.Month

. java.time классы включают удобное перечисление Month,определяя дюжину объектов по одному на каждый месяц года январь-декабрь.

Они пронумерованы от 1 до 12 и определены в правильном порядке с января по декабрь.

В вашей кодовой базе используйтеобъекты этого перечисления, чтобы заменить любое использование простых целых чисел или использование строк имени месяца.Использование Month объектов повсюду обеспечивает безопасность типов, обеспечивает допустимые значения и делает ваш код более самодокументируемым.

В Java EnumSet и EnumMap являются реализациями Set и Map, которые оптимизированы для значений перечисления.Они выполняются очень быстро и занимают очень мало памяти.

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

EnumSet повторяется в естественном порядке, порядке, в котором объявлены константы перечисления.Так что нет необходимости явно сортировать вашу коллекцию.

Класс включает в себя метод getDisplayName для генерации локализованной строки имени месяца.Укажите TextStyle как долго или сокращенно вы хотите текст.И укажите Locale для (а) человеческого языка, используемого в переводе, и (б) культурных норм для решения таких вопросов, как сокращение, пунктуация и использование заглавных букв.

for( Month month : months ) {
    String output = month.getDisplayName( TextStyle.SHORT_STANDALONE , Locale.CANADA_FRENCH );  // Or Locale.US, Locale.ITALY, etc.
    System.out.println( output );
}
0 голосов
/ 20 января 2010

Спасибо всем за предложения, я хотел бы отметить вас всех как принятых.

Вот полученный код:

// 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
0 голосов
/ 20 января 2010

Создать отображение:

month_map = {"January":1,
             "February":2,
             "March":3,
             "April":4} # etc..

Используйте сопоставление для сравнения одного месяца с другим.

OR

Большинство языков / структур имеют объекты для обработки дат. Создайте объекты даты для всех месяцев и сравните их с помощью собственных (если они есть) операторов неравенства или основных функций сортировки:

import datetime
January  = datetime.date(2010,1,1)
February = datetime.date(2010,2,1)
if February < January: print("The world explodes.")
0 голосов
/ 20 января 2010

Добавить префикс для каждого месяца:


Jan -> aJan
Feb -> bFeb
...

Сортировка, затем удаление префикса.

0 голосов
/ 20 января 2010

В течение нескольких месяцев я просто жестко закодировал нужные мне массивы ...

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

Не похоже, что названия месяцев скоро изменятся.

...