Wie kann man den Schaltergehäuseblock verkürzen, der eine Zahl in einen Monatsnamen umwandelt?


110

Gibt es eine Möglichkeit, dies in weniger Zeilen zu schreiben, aber dennoch leicht lesbar?

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
IMHO vidriduchs Antwort ist am besten geeignet. Dies ist wahrscheinlich nicht der einzige Teil Ihres Codes, der Datumsmanipulationen erfordert (obwohl der von Ihnen gezeigte Teil besonders einfach zu codieren ist). Sie sollten ernsthaft in Betracht ziehen, vorhandene, getestete Datumsbibliotheken zu verwenden.
Coredump

2
Ich kenne kein Javascript, aber hat es keine Hashmap wie Pythons Wörterbuch oder C ++ 's std :: map?
Maskierter Mann

28
Soll das nicht für codereview.stackexchange.com sein ?
Loko

2
So viele Antworten, die das Verhalten des Codes ändern, indem sie die Standardeinstellung '' nicht berücksichtigen, was zu einer undefinierten Ausgabe führt, die sich von der des Originals unterscheidet.
Pieter B

2
Dies ist keine doppelte Frage> :( Dies stellt eine völlig andere Frage, die Antwort kann jedoch dieselbe sein.
Leon Gaban

Antworten:


199

Definieren Sie ein Array und ermitteln Sie es anhand des Index.

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

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

23
Stattdessen mm - 1können Sie auch undefinedden ersten Wert (Index 0)
festlegen,

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

77
@ mpez0 Ich denke, ich würde es vorziehen zu wissen, dass jemand es geschafft hat, den 15. Monat zu finden, anstatt zu verbergen, was wahrscheinlich schlechte Daten sind
Izkata

21
@ Touffy Ich denke, ich würde dabei bleiben mm-1, damit months.length==12.
Teepeemm

48
@Touffy Ich würde behaupten, das ist keine Geschmackssache, sondern eine Frage der Vermeidung von cleverem Code . Stellen Sie sich vor, Sie lesen die anderer [undefined, 'January', 'February', ...]- ich bin der Meinung, Ihre erste Reaktion ist WTF?! , was normalerweise kein gutes Zeichen ist ...
miraculixx

81

Was ist mit Array überhaupt nicht zu verwenden :)

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

gemäß dieser Antwort Holen Sie sich den Monatsnamen vom Datum von David Storey


2
Angesichts der fraglichen Problemstellung löst Ihre Antwort dieses Problem nicht wirklich, sondern eine andere Lösung, die in einem anderen Kontext möglicherweise richtig ist. Die ausgewählte Antwort ist immer noch die beste und effizienteste.
TechMaze

6
Es new Date("2009-11-10")wird garantiert, dass nur das Format analysiert wird (siehe diese Spezifikation : ecma-international.org/publications/standards/Ecma-262.htm ). Andere Datumsformate (einschließlich eines in Ihrer Antwort) können analysiert werden, wenn der Browser dies wünscht, und sind daher nicht portierbar.
jb.

58

Versuche dies:

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

Beachten Sie, dass mm dies eine Ganzzahl oder eine Zeichenfolge sein kann und weiterhin funktioniert.

Wenn nicht vorhandene Schlüssel zu einer leeren Zeichenfolge ''(anstelle von undefined) führen sollen, fügen Sie diese Zeile hinzu:

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

JSFiddle .


4
Bei größeren Datensätzen als "Monaten des Jahres" ist dies wahrscheinlich effizienter.
DGM

3
Dies ist effektiv eine Enumeration (dh es unveränderlich), definiert sie als var months = Object.freeze({'1': 'January', '2': 'February'}); //etcSee Aufzählungen in JavaScript?
Alexander

1
@Alexander Wenn Sie den Schlüssel und die Werte tauschen, ähnelt dies einer Aufzählung.
Aber ich bin keine Wrapper-Klasse

26

Sie können stattdessen ein Array erstellen und den Monatsnamen nachschlagen:

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


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

In der Antwort von @CupawnTae finden Sie die Gründe für den Code || ''


anstatt mit 0 Index Anfang könnten Sie halten undefinedan , 0 wie var months = [ undefined, 'January','February','March', .....Sie verwenden , um auf diese Weisemonth = months[mm];
Grijesh Chauhan

@GrijeshChauhan: Bitte vermeiden Sie "cleveren" Code. Die erste Reaktion der nächsten Person wäre wtf. Es ist nur ein '-1', Monate. Die Länge beträgt dann 13, wtf ^ 2. programmers.stackexchange.com/questions/91854/…
RvdK

19

Achtung!

Das, was sofort Alarmglocken auslösen sollte, ist die erste Zeile: var month = '';- Warum wird diese Variable mit einer leeren Zeichenfolge initialisiert und nicht mit nulloder undefined? Möglicherweise war es nur Gewohnheit oder kopierter / eingefügter Code, aber wenn Sie das nicht sicher wissen, ist es nicht sicher, ihn zu ignorieren, wenn Sie Code umgestalten.

Wenn Sie eine Reihe von Monatsnamen verwenden und den Code ändern , um var month = months[mm-1];das Verhalten ändern, weil jetzt Zahlen außerhalb des Bereichs, oder nicht-numerische Werte monthwerdenundefined . Sie wissen vielleicht, dass dies in Ordnung ist, aber es gibt viele Situationen, in denen dies schlecht wäre.

Nehmen wir zum Beispiel an, Sie switchbefinden sich in einer Funktion monthToName(mm)und jemand ruft Ihre Funktion folgendermaßen auf:

var monthName = monthToName(mm);

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

Wenn Sie nun ein Array verwenden und zurückkehren monthName[mm-1], funktioniert der aufrufende Code nicht mehr wie beabsichtigt und sendet undefinedWerte, wenn eine Warnung angezeigt werden soll. Ich sage nicht, dass dies guter Code ist, aber wenn Sie nicht genau wissen, wie der Code verwendet wird, können Sie keine Annahmen treffen.

Oder vielleicht war die ursprüngliche Initialisierung dort, weil ein Code weiter unten davon ausgeht, dass monthes sich immer um eine Zeichenfolge handelt, und so etwas tutmonth.length - dies führt dazu, dass eine Ausnahme für ungültige Monate ausgelöst wird und das aufrufende Skript möglicherweise vollständig beendet wird.

Wenn Sie tun , den gesamten Kontext kennen - zB es ist alles Ihren eigenen Code, und sonst niemand wird es jemals nicht benutzen wollen, und Sie vertrauen sich nicht vergessen Sie die Änderung in der Zukunft gemacht - es kann sicher sein , das Verhalten zu ändern so, aber soooo viele Fehler kommen von dieser Art der Annahme, dass es im wirklichen Leben weitaus besser ist, defensiv zu programmieren und / oder das Verhalten gründlich zu dokumentieren.

Wasmoos Antwort macht es richtig (BEARBEITEN: Eine Reihe anderer Antworten, einschließlich der akzeptierten, wurden jetzt ebenfalls korrigiert ) - Sie können verwenden months[mm-1] || ''oder wenn Sie es vorziehen, auf einen Blick deutlicher zu machen, was passiert, so etwas wie:

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
Bisher hat noch niemand die Verhaltensänderung erwähnt, daher sollte dies beim Re-Factoring von Code berücksichtigt werden.
Mauro

Diese Antwort ist genau richtig. Die meisten anderen Antworten ändern das Verhalten des Codes auf subtile Weise. Dies spielt möglicherweise keine Rolle oder es wird so irritierend schwer, einen Fehler zu finden.
Pieter B

Ah, also ist es immer am besten, eine Var zu initiieren undefined? Spart das Leistung, wenn der Typ konvertiert wird?
Leon Gaban

2
@LeonGaban Es geht nicht um Leistung: Die ursprüngliche Frage initialisierte die Variable mit einer leeren Zeichenfolge und beließ sie dabei, wenn kein gültiger Monat ausgewählt wurde, während viele der anderen Antworten hier diese Tatsache ignorierten und das Verhalten änderten, indem sie zurückkehrten, undefinedwenn die Eingabe nicht erfolgte 't 1..12. Außer unter sehr außergewöhnlichen Umständen übertrifft korrektes Verhalten jedes Mal die Leistung.
CupawnTae

17

Der Vollständigkeit halber möchte ich die aktuellen Antworten ergänzen. Grundsätzlich können Sie das breakSchlüsselwort auslassen und direkt einen geeigneten Wert zurückgeben. Diese Taktik ist nützlich, wenn der Wert nicht in einer vorberechneten Nachschlagetabelle gespeichert werden kann.

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

Auch hier ist die Verwendung einer Nachschlagetabelle oder von Datumsfunktionen prägnanter und subjektiv besser .


16

Sie können dies mit einem Array tun:

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

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

12

Hier ist eine weitere Option, die nur 1 Variable verwendet und dennoch den Standardwert anwendet, ''wenn dieser mmaußerhalb des Bereichs liegt.

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

Die Bereichsprüfung und das Auslösen einer Ausnahme könnten ebenfalls funktionieren. Die Rückgabe von "Fehler" oder "Undefiniert" ist möglicherweise eine Alternative zur leeren Zeichenfolge.
ChuckCottrill

9

Sie können es als Ausdruck anstelle eines Schalters schreiben, indem Sie bedingte Operatoren verwenden:

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

Wenn Sie noch keine verketteten bedingten Operatoren gesehen haben, ist dies zunächst möglicherweise schwerer zu lesen. Wenn Sie es als Ausdruck schreiben, ist ein Aspekt noch einfacher zu erkennen als der ursprüngliche Code. Es ist klar, dass der Code der Variablen einen Wert zuweisen soll month.


1
Ich wollte auch diesen vorschlagen. Es ist tatsächlich sehr gut lesbar, bleibt aber prägnant und eignet sich gut für spärliche Zuordnungen und nicht numerische Schlüssel, was bei der Array-Lösung nicht der Fall ist. PS Ich habe auch eine zufällige unerklärliche Ablehnung meiner Antwort erhalten - wahrscheinlich der gleiche Drive-by-Künstler.
CupawnTae

6

Aufbauend auf der vorherigen Antwort von Cupawn Tae würde ich sie verkürzen auf:

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

Alternativ ja, ich schätze, weniger lesbar:

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

Sie können überspringen (!!months[mm - 1])und einfach tun months[mm - 1].
YingYang

Das würde zu undefiniert führen, wenn der Array-Index außerhalb des Bereichs liegt!
NeilElliott-NSDev

months[mm - 1]wird undefinedfür einen Index zurückgegeben, der außerhalb des Bereichs liegt. Da undefinedes falsch ist, werden Sie ''als Wert von enden month.
YingYang

Wie in anderen Antworten angegeben, können Sie diese Zeile noch weiter vereinfachen:var month = months[mm - 1] || '';
YingYang

Obwohl ich weiter oben bemerkt habe (war nicht da, als ich gepostet habe), ist var month = month [mm - 1] || ''; Welches wäre noch ordentlicher.
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

Wie bei @vidriduch möchte ich die Bedeutung von i20y ("Internationalisierbarkeit") von Code im heutigen Kontext hervorheben und zusammen mit dem einheitlichen Test die folgende prägnante und robuste Lösung vorschlagen.

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

Ich versuche, der ursprünglichen Frage so nahe wie möglich zu kommen, dh die Zahlen 1 bis 12 nicht nur für einen Sonderfall in Monatsnamen umzuwandeln, sondern undefinedbei ungültigen Argumenten zurückzukehren, indem ich einige der zuvor hinzugefügten Kritikpunkte und Inhalte anderer verwende Antworten. (Der Wechsel von undefinedzu ''ist trivial, falls eine genaue Übereinstimmung erforderlich ist.)


0

Ich würde mich für die Lösung von wasmoo entscheiden , aber sie wie folgt anpassen:

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

Es ist wirklich genau derselbe Code, aber anders eingerückt, was IMO ihn lesbarer macht.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.