Come accorciare il blocco case switch convertendo un numero in un nome di mese?


110

C'è un modo per scrivere questo su meno righe, ma comunque facilmente leggibile?

var month = '';

switch(mm) {
    case '1':
        month = 'January';
        break;
    case '2':
        month = 'February';
        break;
    case '3':
        month = 'March';
        break;
    case '4':
        month = 'April';
        break;
    case '5':
        month = 'May';
        break;
    case '6':
        month = 'June';
        break;
    case '7':
        month = 'July';
        break;
    case '8':
        month = 'August';
        break;
    case '9':
        month = 'September';
        break;
    case '10':
        month = 'October';
        break;
    case '11':
        month = 'November';
        break;
    case '12':
        month = 'December';
        break;
}

7
La risposta di Vidriduch IMHO è la più appropriata. Questa probabilmente non è l'unica parte del codice che richiede la manipolazione della data (anche se quella che hai mostrato è particolarmente facile da codificare). Dovresti prendere seriamente in considerazione l'utilizzo di librerie di date esistenti e testate.
coredump

2
Non conosco javascript, ma non ha una hashmap, come il dizionario di Python o lo std :: map di C ++?
Masked Man

28
Non dovrebbe essere per codereview.stackexchange.com ?
Loko

2
Tante risposte che cambiano il comportamento del codice non tenendo conto dell'impostazione predefinita "", il che si traduce in un output non definito, che è diverso da quello che fa l'originale.
Pieter B

2
Questa non è una domanda duplicata> :( questa è una domanda completamente diversa, la risposta potrebbe essere la stessa comunque.
Leon Gaban

Risposte:


199

Definisci un array, quindi ottieni per indice.

var months = ['January', 'February', ...];

var month = months[mm - 1] || '';

23
invece di mm - 1puoi anche impostare undefinedcome primo valore (indice 0) in modo che gli indici dell'array corrispondano ai numeri dei mesi
Touffy

9
var month = month[(mm -1) % 12]
mpez0

77
@ mpez0 Penso che preferirei sapere che qualcuno è riuscito a inventare il mese numero 15, piuttosto che nascondere quelli che probabilmente sono dati non
validi

21
@Touffy penso che rimarrò con mm-1, quindi months.length==12.
Teepeemm

48
@Touffy direi che non è una questione di gusti, ma una questione di evitare il codice intelligente . Immagina di leggere qualcun altro [undefined, 'January', 'February', ...]: è meglio che la tua prima reazione sia WTF ?! , che di solito non è un buon segno ...
miraculixx

81

che ne dici di non usare affatto l'array :)

var objDate = new Date("10/11/2009"),
    locale = "en-us",
    month = objDate.toLocaleString(locale, { month: "long" });

console.log(month);

// or if you want the shorter date: (also possible to use "narrow" for "O"
console.log(objDate.toLocaleString(locale, { month: "short" }));

secondo questa risposta Ottieni il nome del mese da Date da David Storey


2
Data l'affermazione del problema in questione, la tua risposta non sta realmente risolvendo quel problema ma una soluzione diversa che potrebbe essere corretta in un contesto diverso. La risposta selezionata è ancora la migliore e la più efficiente.
TechMaze

6
Solo il new Date("2009-11-10")formato è garantito per essere analizzato (vedere questa specifica: ecma-international.org/publications/standards/Ecma-262.htm ). Altri formati di data (incluso uno nella risposta) possono essere analizzati se il browser lo sceglie, e quindi non sono portabili.
jb.

58

Prova questo:

var months = {'1': 'January', '2': 'February'}; //etc
var month = months[mm];

Nota che mm può essere un numero intero o una stringa e funzionerà comunque.

Se desideri che chiavi non esistenti risultino in una stringa vuota ''(invece di undefined), aggiungi questa riga:

month = (month == undefined) ? '' : month;

JSFiddle .


4
Su set di dati più grandi rispetto ai "mesi dell'anno" questo sarà probabilmente più efficiente.
DGM

3
Questo è effettivamente un enum (cioè rendilo immutabile), definiscilo come var months = Object.freeze({'1': 'January', '2': 'February'}); //etcSee Enums in JavaScript?
Alexander

1
@Alexander Se si scambiano chiave e valori, sì, è simile a un enum.
Ma non sono una classe wrapper

26

Puoi invece creare un array e cercare il nome del mese:

var months = ['January','February','March','April','May','June','July','August','September','October','November','December']


var month = months[mm-1] || '';

Vedi la risposta di @CupawnTae per il razionale dietro il codice || ''


piuttosto che inizio con 0 indice si potrebbe tenere undefineda 0 come var months = [ undefined, 'January','February','March', .....in questo modo si utilizzeràmonth = months[mm];
Grijesh Chauhan

@GrijeshChauhan: evita il codice "intelligente". La prima reazione della persona successiva dovrebbe essere wtf. È solo un '-1', mesi. La lunghezza sarà quindi 13, wtf ^ 2. programmers.stackexchange.com/questions/91854/…
RvdK

19

Stai attento!

La cosa che dovrebbe immediatamente attivare i campanelli d'allarme è la prima riga: var month = '';- perché questa variabile viene inizializzata su una stringa vuota, anziché nullo undefined? Potrebbe essere stata solo un'abitudine o un codice copiato / incollato, ma a meno che tu non lo sappia per certo, non è sicuro ignorarlo quando esegui il refactoring del codice.

Se utilizzi un array di nomi di mesi e modifichi il codice, var month = months[mm-1];stai modificando il comportamento, perché ora per i numeri al di fuori dell'intervallo, o i valori non numerici, monthsarannoundefined . Potresti sapere che questo è ok, ma ci sono molte situazioni in cui questo sarebbe negativo.

Ad esempio, diciamo che sei switchin una funzione monthToName(mm)e qualcuno sta chiamando la tua funzione in questo modo:

var monthName = monthToName(mm);

if (monthName === '') {
  alert("Please enter a valid month.");
} else {
  submitMonth(monthName);
}

Ora, se si passa all'uso di un array e alla restituzione monthName[mm-1], il codice chiamante non funzionerà più come previsto e invierà undefinedvalori quando dovrebbe visualizzare un avviso. Non sto dicendo che questo sia un buon codice, ma a meno che tu non sappia esattamente come viene utilizzato il codice, non puoi fare supposizioni.

O forse l'inizializzazione originale era lì perché un po 'di codice più in basso presume che monthsarà sempre una stringa e fa qualcosa di similemonth.length : questo risulterà in un'eccezione generata per mesi non validi e potenzialmente ucciderà completamente lo script chiamante.

Se tu fai conoscere l'intero contesto - ad esempio, è tutto il proprio codice, e nessun altro è mai andare a usarlo, e si ritiene non te stesso dimenticare che hai fatto il cambiamento in futuro - può essere sicuro di cambiare il comportamento come questo, ma moltissimi bug derivano da questo tipo di presupposto che nella vita reale è molto meglio programmare in modo difensivo e / o documentare accuratamente il comportamento.

La risposta di Wasmoo ha ragione (EDIT: anche una serie di altre risposte, inclusa quella accettata, ora sono state corrette) : puoi usare months[mm-1] || ''o se preferisci rendere più ovvio a colpo d'occhio cosa sta succedendo, qualcosa come:

var months = ['January', 'February', ...];

var month;

if (mm >= 1 && m <= 12) {
  month = months[mm - 1];
} else {
  month = ''; // empty string when not a valid month
}

1
Nessun altro ha ancora menzionato il cambiamento nel comportamento, quindi questo dovrebbe essere preso in considerazione quando si rifatta il codice.
Mauro

Questa risposta è perfetta. La maggior parte delle altre risposte cambia il comportamento del codice in modo sottile. Questo potrebbe non avere importanza o potrebbe diventare così irritantemente difficile trovare bug.
Pieter B

Ah, quindi è sempre meglio avviare una var per undefined? Ciò consente di risparmiare prestazioni se il tipo viene convertito?
Leon Gaban

2
@LeonGaban non si tratta di prestazioni: la domanda originale inizializzava la variabile su una stringa vuota e la lasciava a quella se non era stato selezionato alcun mese valido, mentre molte altre risposte qui ignoravano quel fatto e cambiavano il comportamento restituendo undefinedquando l'input non era 't 1..12. Tranne che in molto casi eccezionali, trionfi di comportamento corretto svolgimento ogni volta.
CupawnTae

17

Per completezza vorrei integrare le risposte attuali. Fondamentalmente, puoi omettere la breakparola chiave e restituire direttamente un valore appropriato. Questa tattica è utile se il valore non può essere memorizzato in una tabella di ricerca precalcolata.

function foo(mm) {
    switch(mm) {
        case '1':  return 'January';
        case '2':  return 'February';
        case '3':  return 'March';
        case '4':  return 'April';
        // [...]
        case '12': return 'December';
    }
    return '';
}

Ancora una volta, l'uso di una tabella di ricerca o di funzioni di data è più succinto e soggettivamente migliore .


16

Puoi farlo usando un array:

var months = ['January', 'February', 'March', 'April', 
              'May', 'June', 'July', 'August', 
              'September', 'October', 'November', 'December'];

var month = months[mm - 1] || '';

12

Ecco un'altra opzione che utilizza solo 1 variabile e applica ancora il valore predefinito ''quando mmè al di fuori dell'intervallo.

var month = ['January', 'February', 'March',
             'April', 'May', 'June', 'July',
             'August', 'September', 'October',
             'November', 'December'
            ][mm-1] || '';

Anche il controllo dell'intervallo e la generazione di un'eccezione potrebbero funzionare. E la restituzione di "Error" o "Undefined" potrebbe essere un'alternativa alla stringa vuota.
ChuckCottrill

9

Puoi scriverlo come un'espressione invece di un interruttore, usando operatori condizionali:

var month =
  mm == 1 ? 'January' :
  mm == 2 ? 'February' :
  mm == 3 ? 'March' :
  mm == 4 ? 'April' :
  mm == 5 ? 'May' :
  mm == 6 ? 'June' :
  mm == 7 ? 'July' :
  mm == 8 ? 'August' :
  mm == 9 ? 'September' :
  mm == 10 ? 'October' :
  mm == 11 ? 'November' :
  mm == 12 ? 'December' :
  '';

Se non hai mai visto operatori condizionali concatenati prima, questo potrebbe sembrare più difficile da leggere all'inizio. Scriverlo come un'espressione rende un aspetto ancora più facile da vedere rispetto al codice originale; è chiaro che l'intenzione del codice è quella di assegnare un valore alla variabile month.


1
Volevo suggerire anche questo. In realtà è molto leggibile pur rimanendo conciso e funzionerebbe bene per mappature sparse e chiavi non numeriche, cosa che la soluzione array non fa. PS Ho ricevuto anche un voto negativo casuale e inspiegabile sulla mia risposta, probabilmente lo stesso artista drive-by.
CupawnTae

6

Basandosi sulla risposta di Cupawn Tae precedente, lo abbreverei a:

var months = ['January', 'February', ...];
var month = (mm >= 1 && mm <= 12) ? months[mm - 1] : '';

In alternativa, sì, apprezzo, meno leggibile:

var month = months[mm - 1] || ''; // as mentioned further up

Puoi saltare (!!months[mm - 1])e semplicemente fare months[mm - 1].
YingYang

Ciò risulterebbe indefinito se l'indice dell'array fosse fuori intervallo!
NeilElliott-NSDev

months[mm - 1]tornerà undefinedper un indice che è fuori intervallo. Poiché undefinedè falso, finirai con ''il valore di month.
YingYang

Come affermato in altre risposte puoi semplificare ancora di più questa riga:var month = months[mm - 1] || '';
YingYang

Anche se ho notato più in alto (non era in giro quando ho postato), var month = months [mm - 1] || ''; Il che sarebbe ancora più ordinato.
NeilElliott-NSDev

4
var getMonth=function(month){
   //Return string to number.
    var strMonth = ['January', 'February', 'March',
             'April', 'May', 'June', 'July',
             'August', 'September', 'October',
             'November', 'December'
            ];
    //return number to string.
    var intMonth={'January':1, 'February':2, 'March':3,
             'April':4, 'May':5, 'June':6, 'July':7,
             'August':8, 'September':9, 'October':10,
             'November':11, 'December':12
            };
    //Check type and return 
    return (typeof month === "number")?strMonth[month-1]:intMonth[month]
}

4

Come @vidriduch, vorrei sottolineare l'importanza di i20y ("internazionalizzazione") del codice nel contesto odierno e suggerire la seguente soluzione concisa e robusta insieme al test unitario.

function num2month(month, locale) {
    if (month != Math.floor(month) || month < 1 || month > 12)
        return undefined;
    var objDate = new Date(Math.floor(month) + "/1/1970");
    return objDate.toLocaleString(locale, {month: "long"});
}

/* Test/demo */
for (mm = 1; mm <= 12; mm++)
    document.writeln(num2month(mm, "en") + " " +
                     num2month(mm, "ar-lb") + "<br/>");
document.writeln(num2month("x", "en") + "<br/>");
document.writeln(num2month(.1, "en") + "<br/>");
document.writeln(num2month(12.5, "en" + "<br/>"));

Cerco di rimanere il più vicino possibile alla domanda originale, cioè trasformare i numeri da 1 a 12 in nomi di mesi, non solo per un caso speciale, ma ci restituisco undefinedin caso di argomenti non validi, usando alcune delle critiche precedentemente aggiunte e contenuti di altri risposte. (La modifica da undefineda ''è banale, nel caso in cui sia necessaria la corrispondenza esatta .)


0

Vorrei la soluzione di wasmoo , ma regolatela in questo modo:

var month = [
    'January',
    'February',
    'March',
    'April',
    'May',
    'June',
    'July',
    'August',
    'September',
    'October',
    'November',
    'December'
][mm-1] || '';

È lo stesso identico codice, in realtà, ma con rientranza diversa, che IMO lo rende più leggibile.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.