Есть ли более быстрый способ сопоставить произвольную строку с именем месяца в Java - PullRequest
5 голосов
/ 21 мая 2010

Я хочу определить, является ли строка названием месяца, и я хочу сделать это относительно быстро. Функция, которая в настоящее время застряла в моем мозгу, выглядит примерно так:

boolean isaMonth( String str ) {
    String[] months = DateFormatSymbols.getInstance().getMonths();
    String[] shortMonths = DateFormatSymbols.getInstance().getShortMonths();
    int i;

    for( i = 0; i<months.length(); ++i;) {
        if( months[i].equals(str) ) return true;
        if( shortMonths[i].equals(str ) return true;
    }
    return false;
}

Однако я буду обрабатывать много текста, передавая по одной строке за раз, и большую часть времени получу наихудший случай прохождения всего цикла и возврата false.

Я видел еще один вопрос, в котором говорилось о регулярном выражении, которое соответствует названию месяца и года, которые могут быть адаптированы к этой ситуации. Будет ли Regex быстрее? Есть ли другое решение, которое может быть быстрее?

Ответы [ 3 ]

3 голосов
/ 21 мая 2010

Почему бы не хранить названия месяцев в HashSet? Это даст вам поиск по постоянному времени вместо поиска по линейному времени, который вы получаете из своего цикла.

import java.util.HashSet;
import java.util.Collections;
import java.text.DateFormatSymbols;

class Test {
  public static void main(String[] args) {

    HashSet<String> months = new HashSet<String>(24);  

    Collections.addAll(months, DateFormatSymbols.getInstance().getMonths());
    Collections.addAll(months, DateFormatSymbols.getInstance().getShortMonths());

    System.out.println(months.contains(args[0]));

  }
}
1 голос
/ 21 мая 2010

HashSet - хорошее решение общего назначения, но я думаю, что вы можете добиться большего. Посмотрите на первую букву месяца - jfmasond - если вы предварительно отфильтровываете их и проверяете только HashSet, если он проходит, он позаботится об огромном количестве ваших сценариев «вернуть ложь».

Вы можете настроить это несколькими способами - один супер простой способ сделать это - использовать оператор switch, хотя таблица поиска будет быстрее. Также обратите внимание, что вам нужно только проверить, находится ли первый символ между a и s, поэтому таблица поиска не должна иметь полное кодовое пространство Юникод (или UTF-8 в зависимости от требований).

Чтобы сделать это еще более эффективным, вы можете создать свою таблицу поиска так, чтобы она содержала первые 2 символа каждого месяца - итоговая таблица поиска не слишком велика, и это значительно уменьшило бы количество слов, которые должны быть проверено на хешсет.

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

1 голос
/ 21 мая 2010

Объедините месяцы и короткие месяцы в один отсортированный массив и выполните двоичный поиск по массиву. Или объедините их в набор (HashSet) и используйте содержимое. Измените все названия месяцев на строчные и сделайте то же самое со значением поиска, если вы хотите, чтобы регистр не учитывался.

Если вы хотите получить номер месяца, объедините их все в карту (HashMap) со значением, равным номеру месяца.

...