2010-01-20 28 views
6

que tienen esta matriz meses:Ordenar meses (con cadenas) algoritmo

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

Y yo quiero tener ordenadas así:

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

Actualmente estoy pensando en un "si/si no "horrible cascada, pero me pregunto si hay alguna otra manera de hacer esto.

La parte mala es que tengo que hacer esto sólo con la "cadena" (es decir, sin utilizar Fecha objeto o algo por el estilo)

lo que sería un buen enfoque?

Respuesta

11

Si tuviera una manera de suministrar un orden de clasificación personalizada, me cree una lista que define el orden correcto:

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

Y a continuación, ordenar por la posición en dicha lista, algo así como:

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

Tiene una matriz con el tipo correcto y ordena según la misma.

Otra solución (si su idioma lo admite) es tener una matriz asociativa de los nombres de los meses a los números (1..12) y utilizar una clasificación de ejecución de comparador personalizado en su matriz.

solución en 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 

(aunque estoy seguro de que un jugador de golf podría hacer que en < 30 caracteres)

Y he aquí una solución en la llanura C: http://www.pnambic.com/CPS/SortAnal/html/MonOrder.html

+0

+1 solución muy elegante! – jspcal

+0

+1 ¿Podría publicar algo un poco más algorítmico? – OscarRyz

+0

Teniendo en cuenta que tiene un conjunto de elementos con nombre, la única forma de hacerlo más algorítmico sería utilizar los hacks basados ​​en el hash:> - p. encontrar un hash que para los nombres de los meses da valores crecientes. –

9

Crear una tabla con nombre-> índice, luego ordena la matriz según su valor en la tabla.

Un par de ejemplos pueden ser útiles, en C# arr.sort(myCompare), en Java Collections.sort(arr, myCompare), en Python arr.sort(myCompare), en PHP usort($arr, 'myCompare'), en C++ sort(vec.begin(), vec.end(), myCompare).

+0

Obtiene mi voto. Asigne cada mes a un índice y luego a la lista rápida – zebrabox

+0

Estoy de acuerdo con la primera parte (crear el nombre-índice) sobre la segunda, "ordenar la matriz según ..." Estoy un poco confundido. – OscarRyz

+0

¿Hablas en serio? quicksort no servirá de nada para tal escala. –

0

para algo así como meses, me gustaría simplemente difícil de código de las matrices que necesitaba ...

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

No es como nombres de los meses van a cambiar en el corto plazo.

+1

Los nombres de los meses cambiarían si tuviera que admitir un idioma que no sea inglés ... –

+2

Puede valer la pena echar un vistazo a [FAQ] (http://stackoverflow.com/faq), especialmente la sección titulada: * Be Nice * –

-1

añadir un prefijo para cada mes:


Jan -> aJan 
Feb -> bFeb 
... 

Ordena, a continuación, quitar el prefijo.

0

crear una asignación:

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

uso del mapeo para comparar un mes a otro.

O

La mayoría de los idiomas/marcos tienen objetos para el manejo de fechas.Crear objetos de fecha para todos los meses y compararlos con el nativo (si está disponible) operadores de desigualdad o funciones básicas de clasificación:

import datetime 
January = datetime.date(2010,1,1) 
February = datetime.date(2010,2,1) 
if February < January: print("The world explodes.") 
0

Gracias a todos por las sugerencias, me gustaría señalar que todos como aceptado.

Aquí está el código resultante:

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

Hablando desde un POV de Java, voy a proxeneta (como hago a menudo) google-collections (pronto a ser reemplazado por Guava):

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

... y listo.

No escriba usted mismo si alguien más lo ha hecho, probablemente de manera más eficiente y con un API más agradable de lo que probablemente haría.

No es de utilidad en el caso general, pero por si acaso alguna gente Java tienen el mismo problema ...

+0

Desafortunadamente no tengo acceso a java aquí. De lo contrario, hubiera utilizado 'SimpleDateFormat.parse' + implementación' Comparable' personalizada – OscarRyz

1

colegas,

veo el problema emisión/negocio tiene una duración de más de 2 años. decidí escribir comparador para ordenar nombres meses (almacenados como cadenas) correctamente. También posee nombres de los meses de configuración regional deseada ============== Comparador =======================

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

    } 
} 

y simple clase de prueba a 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)); 
     } 
    } 

} 

disfrutarlo, funciona como un encanto.

0

tl; dr

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

Enum

Si su lenguaje proporciona una potente función de enum al igual que Java, definen una docena de objetos. Ver Oracle Tutorial.

java.time.Month

Las clases incluyen java.time la mano Month enumeración, la definición de una docena de objetos uno por cada mes del año, de enero a diciembre.

Se numeran 1-12, y se definen en el orden apropiado, enero a diciembre.

En su base de código, utilice los objetos de esta enumeración para reemplazar cualquier uso de simples números enteros o uso de cadenas de nombres de mes. El uso de objetos a lo largo Month proporciona seguridad de tipos, asegura valores válidos, y hace que el código sea más auto-documentado.

En Java, la EnumSet y EnumMap son implementaciones de Set y Map que están optimizados para valores de enumeración. Se ejecutan muy rápido y toman muy poca memoria.

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

Los EnumSet itera en orden natural, el orden en que se declaran las constantes de enumeración. Por lo tanto, no es necesario ordenar explícitamente su colección.

La clase incluye un método getDisplayName para generar una cadena localizada del nombre del mes. Especifique un TextStyle durante cuánto tiempo o abreviado desea el texto. Y especifique un Locale para (a) el lenguaje humano para usar en la traducción, y (b) las normas culturales para decidir cuestiones tales como abreviatura, puntuación y uso de mayúsculas y minúsculas.

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