2010-05-21 4 views
5

Quiero determinar si una cadena es el nombre de un mes y quiero hacerlo con relativa rapidez. La función que se ha quedado atascado actualmente en mi cerebro es algo así como:¿Existe un método más rápido para hacer coincidir un nombre de cadena arbitraria con el mes en Java

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; 
} 

Sin embargo, será de proceso mucho texto, pasa una cuerda a la vez a esta función, y la mayor parte del tiempo que va a obtener el el peor caso de pasar por todo el ciclo y devolver falso.

Vi otra pregunta que hablaba de un Regex para coincidir con un nombre de mes y un año que podría adaptarse para esta situación. ¿La Regex sería más rápida? ¿Hay alguna otra solución que pueda ser más rápida?

+0

para empezar, puede mover/hacer meses, variables de miembros estáticos shortMonths (asignar solo una vez) .. –

+0

una expresión regular debe ser rápida. Una máquina de estado hecha a medida más rápido. – SyntaxT3rr0r

Respuesta

3

¿Por qué no almacena los nombres de los meses en un HashSet? Esto le dará una búsqueda de tiempo constante en lugar de la búsqueda de tiempo lineal que está obteniendo de su ciclo.

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])); 

    } 
} 
+2

¿Qué tal 'Collections.addAll (months, DateFormatSymbols.getInstance(). GetMonths())'? – msandiford

+0

Buena llamada, cambió el código – dbyrne

+0

Esta respuesta me ayudó a ir en la dirección correcta. También me gusta algo de lo que Kevin Day dice un par de respuestas, e intentaré incorporar algo de eso un poco más tarde. – jonc

1

Combina meses y shortMonths en una única matriz ordenada y realiza una búsqueda binaria en la matriz. O unirlos a ambos en un conjunto (HashSet) y usar contiene. Cambia todos los nombres de los meses a minúsculas y haz lo mismo con el valor de búsqueda, si quieres ser insensible a mayúsculas y minúsculas.

Si desea poder recuperar el número del mes, combínelos en un Mapa (HashMap) con el valor correspondiente al número de mes.

1

HashSet es una buena solución de propósito general, pero creo que puede hacerlo mejor. Eche un vistazo a la primera letra de los meses, jfmasond, si realiza un prefiltrado y solo realiza la comprobación de HashSet si pasa, se ocupará de una gran cantidad de escenarios de "devolución falsa".

Puede configurar esto de varias maneras: una manera muy fácil de hacerlo es usar una declaración de cambio, aunque una tabla de búsqueda sería más rápida. Tenga en cuenta también que solo necesita hacer la comprobación si el primer carácter está entre ay a, de modo que una tabla de búsqueda no tiene que tener el espacio de código completo de unicode (o UTF-8 según los requisitos).

Para que esto sea aún más efectivo, puede construir su tabla de búsqueda para que contenga los primeros 2 caracteres de cada mes; la tabla de búsqueda resultante no es demasiado grande, y esto reduciría drásticamente el número de palabras que necesitan ser verificado contra el hashset.

PD: antes de hacer algo de esto, debe hacer algunos perfiles y asegurarse de que esta es el área de su código que en realidad es el cuello de botella.

+0

Bien pensado en la tabla de búsqueda. El proyecto completo aún no se ha unido, así que esperaré en la tabla de búsqueda hasta que pueda hacer un mejor perfil – jonc

+0

básicamente describiendo la creación de su propia máquina de estado muy específica (que comencé a comentar en el OP antes de notar su responder). En Java, una instrucción * switch * cuidadosamente construida debe ser más rápida que una búsqueda de tabla: básicamente, usted quiere que su instrucción switch se convierta en el código de operación JVM * tableswitch * (no el * lookupswitch * one, que es más lento). Al hacer esto, esquivas la tabla de búsqueda y por lo tanto serás más rápido (menos a menudo invalidar cachés, etc.).Ahora, por supuesto, dudo que el OP realmente necesite este tipo de optimizaciones en su caso. – SyntaxT3rr0r

+0

@webinator - buena información - No he hecho suficiente spelunking en el bytecode de Java, pero su descripción tiene sentido. Me interesa saber qué causa la interpretación del código de operación tableswitch vs lookupswitch. Lo buscaré. –

Cuestiones relacionadas