Was ist der beste (effizienteste) Weg, um alle Schlüssel eines Objekts in Kleinbuchstaben umzuwandeln?
Lesezeit: 7 Minuten
João Pinto Jerónimo
Ich bin darauf gekommen
function keysToLowerCase (obj) {
var keys = Object.keys(obj);
var n = keys.length;
while (n--) {
var key = keys[n]; // "cache" it, for less lookups to the array
if (key !== key.toLowerCase()) { // might already be in its lower case version
obj[key.toLowerCase()] = obj[key] // swap the value to a new lower case key
delete obj[key] // delete the old key
}
}
return (obj);
}
Aber ich bin mir nicht sicher, wie sich v8 damit verhalten wird, wird es zum Beispiel wirklich die anderen Schlüssel löschen oder werden nur Referenzen gelöscht und der Garbage Collector wird mich später beißen?
Außerdem habe ich erstellt diese Prüfungenich hoffe, Sie könnten Ihre Antwort dort hinzufügen, damit wir sehen können, wie sie zusammenpassen.
BEARBEITEN 1:
Anscheinend ist es den Tests zufolge schneller, wenn wir nicht prüfen, ob der Schlüssel bereits in Kleinbuchstaben geschrieben ist, aber da er schneller ist, wird er mehr Unordnung schaffen, wenn er dies ignoriert und einfach neue Kleinbuchstaben erstellt? Wird der Garbage Collector damit zufrieden sein?
Können Sie ein neues Objekt erstellen, anstatt das vorhandene zu ändern? Sie würden alle Löschungen überspringen.
– Jason Orendorff
22. September 2012 um 0:32 Uhr
Ich denke, Ihr Code ist vernünftig, wie er ist. “Es ist schneller, wenn wir nicht prüfen, ob der Schlüssel bereits in Kleinbuchstaben ist, aber … wird es mehr Unordnung schaffen, wenn dies ignoriert und nur neue Kleinbuchstaben erstellt werden?” – Dieser Code funktioniert nicht wirklich (er löscht am Ende alle Schlüssel, die bereits Kleinbuchstaben waren), also spielt es wirklich keine Rolle, wie schnell er ist …
– nnnnn
22. September 2012 um 0:33 Uhr
@JasonOrendorff anscheinend ist es langsamer und es würde jedes Mal ein unnötiges Objekt erstellen, und der Garbage Collector wäre damit nicht zufrieden …
– João Pinto Jerónimo
22. September 2012 um 0:40 Uhr
@JoãoPintoJerónimo Was Sie in Ihren Geschwindigkeitstests sehen, ist, dass der Code Tausende Male auf demselben Objekt ausgeführt wird. Nach einmaligen Testläufen gibt es natürlich keine Arbeit mehr; Alle Tasten sind bereits Kleinbuchstaben. Wenn Sie es testen, indem Sie viele Objekte mit vielen Schlüsseln erstellen: jsperf.com/object-keys-to-lower-case/7 dann sind alle drei Implementierungen dramatisch langsamer, aber das Erstellen eines neuen Objekts ist sowohl in Firefox als auch in Chrome etwas schneller.
– Jason Orendorff
22. September 2012 um 3:28 Uhr
Oh, ich verstehe @JasonOrendorff … Ich werde die Tests noch einmal überarbeiten
– João Pinto Jerónimo
22. September 2012 um 3:34 Uhr
etwas
Das am schnellsten Ich komme mit, wenn Sie ein neues Objekt erstellen:
var key, keys = Object.keys(obj);
var n = keys.length;
var newobj={}
while (n--) {
key = keys[n];
newobj[key.toLowerCase()] = obj[key];
}
Ich bin mit dem aktuellen Innenleben von v8 nicht vertraut genug, um Ihnen eine endgültige Antwort zu geben. Vor ein paar Jahren habe ich ein Video gesehen, in dem die Entwickler über Objekte gesprochen haben, und IIRC wird nur die Referenzen löschen und den Garbage Collector sich darum kümmern lassen. Aber es ist Jahre her, also selbst wenn es damals so war, muss es jetzt nicht so sein.
Wird es dich später beißen? Es hängt davon ab, was Sie tun, aber wahrscheinlich nicht. Es ist sehr üblich, kurzlebige Objekte zu erstellen, sodass der Code dafür optimiert ist, damit umzugehen. Aber jede Umgebung hat ihre Grenzen, und vielleicht beißt sie dich. Sie müssen mit tatsächlichen Daten testen.
Dies ist die beste Antwort, aber @JasonOrendorff verdient auch Anerkennung dafür.
– João Pinto Jerónimo
22. September 2012 um 22:28 Uhr
Ich denke, das braucht eine var vor dem key = keys[n] ?
– Andreas Ferrier
6. Juni 2013 um 15:52 Uhr
@AndrewFerrier Richtig. Fest.
– etwas
23. Juli 2013 um 21:27 Uhr
Dies macht nur eine Ebene, wenn Sie etwas wie {A:1, B : { C: 2 }} haben. A und B würden geändert, aber nicht C
– Michael Warner
17. Januar 2017 um 21:31 Uhr
@MichaelWarner Das ist richtig, es berührt nur die Tasten in dem Objekt, das Sie ihm geben, und berührt die Kinder nicht. Darum ging es in der Frage. Es sieht so aus, als wollten Sie eine tiefe Kopie machen, aber das ist ein dunkler tiefer Kaninchenbau …
– etwas
18. Januar 2017 um 3:20 Uhr
Yves M.
Verwenden Object.fromEntries (ES10)
Native und unveränderliche Lösung mit dem neuen Object.fromEntries Methode:
Eine schöne Sache ist, dass diese Methode das Gegenteil von bewirkt Object.entriessodass Sie jetzt zwischen der Objekt- und der Array-Darstellung hin und her wechseln können.
let objectKeysToLowerCase = function (origObj) {
return Object.keys(origObj).reduce(function (newObj, key) {
let val = origObj[key];
let newVal = (typeof val === 'object') ? objectKeysToLowerCase(val) : val;
newObj[key.toLowerCase()] = newVal;
return newObj;
}, {});
}
Es ist prägnant, behandelt verschachtelte Objekte wieder und gibt ein neues Objekt zurück, anstatt das Original zu ändern.
In meinen begrenzten lokalen Tests ist diese Funktion schneller als die andere derzeit aufgeführte rekursive Lösung (einmal behoben). Ich würde es gerne mit den anderen vergleichen, aber jsperf ist im Moment nicht verfügbar (???).
Es ist auch in ES5.1 geschrieben, also sollte es laut den Dokumenten auf MDN in FF 4+, Chrome 5+, IE 9.0+, Opera 12+, Safari 5+ (also so ziemlich alles) funktionieren.
Ich würde mir nicht allzu viele Gedanken über den Aspekt der Garbage Collection machen. Sobald alle Verweise auf das alte Objekt zerstört sind, werden es aber die GC’s sein Neu Das Objekt wird im Grunde immer noch auf alle seine Eigenschaften verweisen, also nicht.
Alle Funktionen, Arrays oder RegExp werden durch Verweis “kopiert”. In Bezug auf den Speicher werden selbst Strings durch diesen Prozess nicht dupliziert, da die meisten (alle?) modernen JS-Engines Benutzer sind string internieren. Ich denke, das lässt nur die Zahlen, Booleans und die Objekte, die die ursprüngliche Struktur bildeten, übrig, um GC’d zu werden.
Beachten Sie, dass (alle Implementierungen) dieses Prozesses Werte verlieren, wenn das Original mehrere Eigenschaften mit derselben Darstellung in Kleinbuchstaben hat. Dh:
Natürlich ist das manchmal genau das, was Sie wollen.
Update 17.07.2018
Einige Leute haben bemerkt, dass die ursprüngliche Funktion mit Arrays nicht gut funktioniert. Hier ist eine erweiterte, widerstandsfähigere Version. Es wiederholt sich korrekt durch Arrays und funktioniert, wenn der Anfangswert ein Array oder ein einfacher Wert ist:
let objectKeysToLowerCase = function (input) {
if (typeof input !== 'object') return input;
if (Array.isArray(input)) return input.map(objectKeysToLowerCase);
return Object.keys(input).reduce(function (newObj, key) {
let val = input[key];
let newVal = (typeof val === 'object') && val !== null ? objectKeysToLowerCase(val) : val;
newObj[key.toLowerCase()] = newVal;
return newObj;
}, {});
};
Der loDash/fp-Weg, ganz nett, da es im Wesentlichen ein Einzeiler ist
import {
mapKeys
} from 'lodash/fp'
export function lowerCaseObjectKeys (value) {
return mapKeys(k => k.toLowerCase(), value)
}
Szymon Toda
Die Verwendung von forEach scheint in meinen Tests etwas schneller zu sein – und die ursprüngliche Referenz ist weg, sodass das Löschen der neuen sie in die Reichweite des gc bringt
function keysToLowerCase(obj){
Object.keys(obj).forEach(function (key) {
var k = key.toLowerCase();
if (k !== key) {
obj[k] = obj[key];
delete obj[key];
}
});
return (obj);
}
var O={ONE:1,two:2,tThree:3,FOUR:4,Five:5,SIX:{a:1,b:2,c:3,D:4,E:5}}; TastenToLowerCase(O);
immer noch nicht schneller als meine … Die umgekehrte While-Schleife ist die schnellste Schleife in Javascript, siehe hier: jsperf.com/javascript-loop (Die umgekehrte While-Schleife ist schneller, aber die Ergebnisse zeigen eine andere Sache als die schnellste, möglicherweise von alten Browsern, die sie zuvor ausgeführt haben.)
– João Pinto Jerónimo
22. September 2012 um 1:22 Uhr
keine reine Funktion – Sie mutieren das Argument
– Eugen Fidelin
26. Oktober 2017 um 15:13 Uhr
11758500cookie-checkWas ist der beste (effizienteste) Weg, um alle Schlüssel eines Objekts in Kleinbuchstaben umzuwandeln?yes
Können Sie ein neues Objekt erstellen, anstatt das vorhandene zu ändern? Sie würden alle Löschungen überspringen.
– Jason Orendorff
22. September 2012 um 0:32 Uhr
Ich denke, Ihr Code ist vernünftig, wie er ist. “Es ist schneller, wenn wir nicht prüfen, ob der Schlüssel bereits in Kleinbuchstaben ist, aber … wird es mehr Unordnung schaffen, wenn dies ignoriert und nur neue Kleinbuchstaben erstellt werden?” – Dieser Code funktioniert nicht wirklich (er löscht am Ende alle Schlüssel, die bereits Kleinbuchstaben waren), also spielt es wirklich keine Rolle, wie schnell er ist …
– nnnnn
22. September 2012 um 0:33 Uhr
@JasonOrendorff anscheinend ist es langsamer und es würde jedes Mal ein unnötiges Objekt erstellen, und der Garbage Collector wäre damit nicht zufrieden …
– João Pinto Jerónimo
22. September 2012 um 0:40 Uhr
@JoãoPintoJerónimo Was Sie in Ihren Geschwindigkeitstests sehen, ist, dass der Code Tausende Male auf demselben Objekt ausgeführt wird. Nach einmaligen Testläufen gibt es natürlich keine Arbeit mehr; Alle Tasten sind bereits Kleinbuchstaben. Wenn Sie es testen, indem Sie viele Objekte mit vielen Schlüsseln erstellen: jsperf.com/object-keys-to-lower-case/7 dann sind alle drei Implementierungen dramatisch langsamer, aber das Erstellen eines neuen Objekts ist sowohl in Firefox als auch in Chrome etwas schneller.
– Jason Orendorff
22. September 2012 um 3:28 Uhr
Oh, ich verstehe @JasonOrendorff … Ich werde die Tests noch einmal überarbeiten
– João Pinto Jerónimo
22. September 2012 um 3:34 Uhr