Jak skrócić blok obudowy przełącznika, konwertując numer na nazwę miesiąca?

110

Czy istnieje sposób na zapisanie tego w mniejszej liczbie wierszy, ale nadal łatwe do odczytania?

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;
}
Leon Gaban
źródło
7
Odpowiedź IMHO vidriduch jest najbardziej odpowiednia. Prawdopodobnie nie jest to jedyna część twojego kodu, która wymaga manipulacji datą (nawet jeśli ta, którą pokazałeś, jest szczególnie łatwa do zakodowania). Powinieneś poważnie rozważyć użycie istniejących, przetestowanych bibliotek Date.
coredump
2
Nie znam javascript, ale czy nie ma on hashmap, jak słownik Pythona lub std :: map w C ++?
Masked Man
28
Czy to nie ma dotyczyć codereview.stackexchange.com ?
Loko
2
Tak wiele odpowiedzi zmienia zachowanie kodu, nie biorąc pod uwagę domyślnej wartości „”, co skutkuje niezdefiniowanymi danymi wyjściowymi, które różnią się od tego, co robi oryginał.
Pieter B
2
To nie jest zduplikowane pytanie> :( to jest pytanie zupełnie inne, jednak odpowiedź może być taka sama.
Leon Gaban

Odpowiedzi:

199

Zdefiniuj tablicę, a następnie pobierz według indeksu.

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

var month = months[mm - 1] || '';
xdazz
źródło
23
zamiast mm - 1ciebie możesz również ustawić undefinedjako pierwszą wartość (indeks 0), aby indeksy tablicy były zgodne z numerami miesięcy
Touffy
9
var month = month[(mm -1) % 12]
mpez0
77
@ mpez0 Myślę, że wolałbym wiedzieć, że komuś udało się wymyślić numer 15 miesiąca, niż ukryć prawdopodobnie złe dane
Izkata
21
@Touffy, myślę, że zostanę z mm-1, więc to months.length==12.
Teepeemm
48
@Touffy Twierdziłbym, że to nie kwestia gustu, ale unikania sprytnego kodu . Wyobraź sobie, że czytasz kogoś innego [undefined, 'January', 'February', ...]- najlepiej, że twoją pierwszą reakcją jest WTF ?! , co zwykle nie jest dobrym znakiem ...
miraculixx
81

a co by w ogóle nie używać tablicy :)

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

zgodnie z tą odpowiedzią Pobierz nazwę miesiąca z Data od Davida Storeya

vidriduch
źródło
2
Biorąc pod uwagę stwierdzenie problemu, twoja odpowiedź nie jest tak naprawdę rozwiązaniem tego problemu, ale jakimś innym rozwiązaniem, które może być poprawne w innym kontekście. Wybrana odpowiedź jest nadal najlepsza i najbardziej skuteczna.
TechMaze
6
Tylko new Date("2009-11-10")format ma być przeanalizowany (zobacz tę specyfikację : ecma-international.org/publications/standards/Ecma-262.htm ). Inne formaty dat (w tym jeden w Twojej odpowiedzi) mogą być analizowane, jeśli tak zdecyduje przeglądarka, i dlatego nie są przenośne.
jb.
58

Spróbuj tego:

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

Zauważ, że mmmoże to być liczba całkowita lub łańcuch i nadal będzie działać.

Jeśli chcesz, aby nieistniejące klucze skutkowały pustym ciągiem ''(zamiast undefined), dodaj tę linię:

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

JSFiddle .

Ale nie jestem klasą opakowującą
źródło
4
W przypadku zbiorów danych większych niż „miesiące w roku” będzie to prawdopodobnie bardziej wydajne.
DGM
3
W praktyce jest to wyliczenie (tzn. Uczynienie go niezmiennym), zdefiniować je jako var months = Object.freeze({'1': 'January', '2': 'February'}); //etcZobacz wyliczenia w JavaScript?
Alexander
1
@Alexander Jeśli zamienisz klucz i wartości, to tak, jest to podobne do wyliczenia.
Ale nie jestem z klasy Wrapper
26

Zamiast tego możesz utworzyć tablicę i wyszukać nazwę miesiąca:

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


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

Zobacz odpowiedź @CupawnTae, aby poznać uzasadnienie kodu || ''

Alex
źródło
zamiast początek 0 indeksu można zachować undefinedw 0 jak var months = [ undefined, 'January','February','March', .....W ten sposób można wykorzystaćmonth = months[mm];
Grijesh Chauhan
@GrijeshChauhan: unikaj „sprytnego” kodu. Pierwsza reakcja następnej osoby to wtf. To tylko `` -1 '' miesięcy, a długość będzie wynosić 13, wtf ^ 2. programmers.stackexchange.com/questions/91854/ ...
RvdK
19

Bądź ostrożny!

To, co powinno natychmiast wywołać dzwonki alarmowe, to pierwsza linia: var month = '';- dlaczego ta zmienna jest inicjalizowana jako pusty łańcuch, a nie nulllub undefined? Być może był to po prostu nawyk lub kopiowanie / wklejanie kodu, ale jeśli nie wiesz tego na pewno, nie jest bezpiecznie ignorować go podczas refaktoryzacji kodu.

Jeśli używasz tablicy nazw miesięcy i zmienisz swój kod var month = months[mm-1];, zmieniasz zachowanie, ponieważ teraz dla liczb spoza zakresu lub wartości nienumerycznych monthbędzie undefined. Możesz wiedzieć, że to jest w porządku, ale jest wiele sytuacji, w których byłoby to złe.

Na przykład, powiedzmy, że twoja switchjest w funkcji monthToName(mm), a ktoś wywołuje twoją funkcję w ten sposób:

var monthName = monthToName(mm);

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

Teraz, jeśli zmienisz na używanie tablicy i zwrócisz monthName[mm-1], kod wywołujący nie będzie już działał zgodnie z przeznaczeniem i prześle undefinedwartości, gdy ma wyświetlić ostrzeżenie. Nie twierdzę, że to dobry kod, ale jeśli nie wiesz dokładnie, jak kod jest używany, nie możesz robić założeń.

A może oryginalna inicjalizacja była tam, ponieważ jakiś kod w dalszej części linii zakłada, że monthzawsze będzie to ciąg, i robi coś w rodzajumonth.length - spowoduje to wyrzucenie wyjątku dla nieprawidłowych miesięcy i potencjalnie całkowicie zabije skrypt wywołujący.

Jeśli zrobić znać cały kontekst - np to wszystko swój własny kod, a nikt inny kiedykolwiek będzie go używać, i ufasz sobie nie zapomnieć dokonaniu kiedyś zmieni się w przyszłości - może być bezpieczny, aby zmienić zachowanie w ten sposób, ale bardzo wiele błędów wynika z tego rodzaju założenia, że ​​w prawdziwym życiu znacznie lepiej jest programować defensywnie i / lub dokładnie dokumentować zachowanie.

Odpowiedź Wasmoo ma rację (EDYTUJ: kilka innych odpowiedzi, w tym zaakceptowana, również zostało naprawionych) - możesz użyć months[mm-1] || ''lub jeśli wolisz, aby było bardziej oczywiste na pierwszy rzut oka, co się dzieje, na przykład:

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

var month;

if (mm >= 1 && m <= 12) {
  month = months[mm - 1];
} else {
  month = ''; // empty string when not a valid month
}
CupawnTae
źródło
1
Nikt jeszcze nie wspomniał o zmianie w zachowaniu, więc należy to wziąć pod uwagę podczas ponownego faktorowania kodu.
Mauro
Ta odpowiedź jest trafna. Większość pozostałych odpowiedzi w subtelny sposób zmienia zachowanie kodu. Może to nie mieć znaczenia lub może stać się irytująco trudne do znalezienia błędu.
Pieter B
Ach, więc zawsze najlepiej jest zainicjować var ​​to undefined? Czy to oszczędza wydajność, jeśli typ zostanie przekonwertowany?
Leon Gaban
2
@LeonGaban nie chodzi o wydajność: pierwotne pytanie zainicjowało zmienną w pusty ciąg i pozostawiło ją tak, jeśli nie wybrano prawidłowego miesiąca, podczas gdy wiele innych odpowiedzi tutaj zignorowało ten fakt i zmieniło zachowanie, zwracając, undefinedgdy dane wejściowe nie były 't 1..12. Z wyjątkiem bardzo wyjątkowych okoliczności, prawidłowe zachowanie jest zawsze ważniejsze od wydajności.
CupawnTae
17

Dla kompletności chciałbym uzupełnić aktualne odpowiedzi. Zasadniczo można pominąć breaksłowo kluczowe i bezpośrednio zwrócić odpowiednią wartość. Ta taktyka jest przydatna, jeśli wartość nie może być przechowywana we wstępnie obliczonej tabeli przeglądowej.

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

Ponownie, użycie tabeli przeglądowej lub funkcji daty jest bardziej zwięzłe i subiektywnie lepsze .

Gerard
źródło
16

Możesz to zrobić za pomocą tablicy:

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

var month = months[mm - 1] || '';
Stuart Wagner
źródło
12

Oto kolejna opcja, która używa tylko 1 zmiennej i nadal stosuje wartość domyślną, ''gdy mmjest poza zakresem.

var month = ['January', 'February', 'March',
             'April', 'May', 'June', 'July',
             'August', 'September', 'October',
             'November', 'December'
            ][mm-1] || '';
Wasmoo
źródło
Sprawdzanie zakresu i zgłaszanie wyjątku również może działać. A zwrócenie „Błąd” lub „Niezdefiniowany” może być alternatywą dla pustego ciągu.
ChuckCottrill
9

Możesz zapisać to jako wyrażenie zamiast przełącznika, używając operatorów warunkowych:

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' :
  '';

Jeśli wcześniej nie widziałeś łańcuchowych operatorów warunkowych, na początku może się to wydawać trudniejsze do odczytania. Zapisanie go jako wyrażenia sprawia, że ​​jeden aspekt jest jeszcze łatwiejszy do zobaczenia niż oryginalny kod; jasne jest, że intencją kodu jest przypisanie wartości zmiennej month.

Guffa
źródło
1
Miałem zamiar zasugerować to również. W rzeczywistości jest bardzo czytelny, a jednocześnie pozostaje zwięzły, i działałby dobrze w przypadku rzadkich mapowań i kluczy nienumerycznych, czego nie zapewnia rozwiązanie tablicowe. PS. Otrzymałem też losowy, niewyjaśniony głos negatywny na moją odpowiedź - prawdopodobnie ten sam artysta, który jeździł.
CupawnTae
6

Opierając się na poprzedniej odpowiedzi Cupawn Tae , skróciłbym ją do:

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

Ewentualnie tak, doceniam, mniej czytelne:

var month = months[mm - 1] || ''; // as mentioned further up
NeilElliott-NSDev
źródło
Możesz pominąć (!!months[mm - 1])i po prostu zrobićmonths[mm - 1] .
YingYang
To spowodowałoby undefined, gdyby indeks tablicy był poza zakresem!
NeilElliott-NSDev
months[mm - 1]zwróci undefinedwartość indeksu, który jest poza zakresem. Odundefined jest fałszywe, otrzymasz ''jako wartość month.
YingYang
Jak stwierdzono w innych odpowiedziach, możesz jeszcze bardziej uprościć tę linię: var month = months[mm - 1] || '';
YingYang
Chociaż zauważyłem wyżej (nie było go w pobliżu, kiedy pisałem), var month = months [mm - 1] || ''; Co byłoby jeszcze ładniejsze.
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]
}
Laxmikant Dange
źródło
4

Podobnie jak @vidriduch, chciałbym podkreślić znaczenie i20y („internacjonalizacji”) kodu w dzisiejszym kontekście i zasugerować następujące zwięzłe i solidne rozwiązanie wraz z testem jednostkowym.

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/>"));

Staram się pozostać jak najbliżej pierwotnego pytania, tj. Przekształcić liczby od 1 do 12 w nazwy miesięcy, nie tylko dla jednego specjalnego przypadku, ale powrócić undefinedw przypadku niepoprawnych argumentów, wykorzystując część wcześniej dodanej krytyki i treści innych odpowiedzi. (Zmiana z undefinedna ''jest trywialna, jeśli potrzebne jest dokładne dopasowanie).

Sztylet
źródło
0

Pójdę za wasmoo roztworu „s, ale dostosować go tak:

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

W rzeczywistości jest to dokładnie ten sam kod, ale z innymi wcięciami, dzięki czemu jest on bardziej czytelny.

John Slegers
źródło