Objektschlüssel rekursiv umbenennen

Lesezeit: 8 Minuten

Objektschlussel rekursiv umbenennen
Andy Gee

Ich habe eine rekursive Funktion, um die Schlüsselnamen eines Objekts umzubenennen, aber ich kann nicht herausfinden, wie man 2 der Schlüssel umbenennt (Problemschlüssel sind Objekte).

Ich denke, das Problem liegt darin, dass ich nach dem Objekttyp suche, aber wie kann ich den Schlüssel an dieser Stelle umbenennen?

Die tatsächlichen Arrays sind sehr groß, aber eine abgespeckte Version ist unten.

Jede Hilfe geschätzt.

var keys_short = ['ch','d','u','tz'];
var keys_long = ['children','data','user_id','time_zone'];
function refit_keys(o){
    build = {};
    for (var i in o){
        if(typeof(o[i])=="object"){
            o[i] = refit_keys(o[i]);
            build = o;
        }else{
            var ix = keys_short.indexOf(i);
            if(ix!=-1){
                build[keys_long[ix]] = o[keys_short[ix]];
            }
        }
    }
    return build;
}

Meine Eingabe sieht so aus:

{
    "id":"1",
    "ch":[
        {
            "id":"3",
            "ch":[
            ],
            "d":{
                "u":"3",
                "tz":"8.00"
            }
        },
        {
            "id":"45",
            "ch":[
                {
                    "id":"70",
                    "ch":[
                        {
                            "id":"43",
                            "ch":[
                            ],
                            "d":{
                                "u":"43",
                                "tz":"-7.00"
                            }
                        }
                    ],
                    "d":{
                        "u":"70",
                        "tz":"-7.00"
                    }
                }
            ],
            "d":{
                "u":"45",
                "tz":"-7.00"
            }
        }
    ],
    "d":{
        "u":"1",
        "tz":"8.00"
    }
}

Meine Ausgabe wie folgt:

{
    "id":"1",
    "ch":[
        {
            "id":"3",
            "ch":[
            ],
            "d":{
                "user_id":"3",
                "time_zone":"8.00"
            }
        },
        {
            "id":"45",
            "ch":[
                {
                    "id":"70",
                    "ch":[
                        {
                            "id":"43",
                            "ch":[
                            ],
                            "d":{
                                "user_id":"43",
                                "time_zone":"-7.00"
                            }
                        }
                    ],
                    "d":{
                        "user_id":"70",
                        "time_zone":"-7.00"
                    }
                }
            ],
            "d":{
                "user_id":"45",
                "time_zone":"-7.00"
            }
        }
    ],
    "d":{
        "user_id":"1",
        "time_zone":"8.00"
    }
}

Objektschlussel rekursiv umbenennen
TJ Crowder

Da gibt es ein paar Probleme.

Einer ist, dass du zum Opfer fällst Der Horror der impliziten Globalen indem Sie es unterlassen, Ihre build variabel in der Funktion.

Aber die Logik hat auch Probleme, hier ist eine minimale Überarbeitung:

var keys_short = ["ch","d","u","tz"];
var keys_long = ["children","data","user_id","time_zone"];
function refit_keys(o){
    var build, key, destKey, ix, value;

    // Only handle non-null objects
    if (o === null || typeof o !== "object") {
        return o;
    }

    // Handle array just by handling their contents
    if (Array.isArray(o)) {
        return o.map(refit_keys);
    }

    // We have a non-array object
    build = {};
    for (key in o) {
        // Get the destination key
        ix = keys_short.indexOf(key);
        destKey = ix === -1 ? key : keys_long[ix];

        // Get the value
        value = o[key];

        // If this is an object, recurse
        if (typeof value === "object") {
            value = refit_keys(value);
        }

        // Set it on the result using the destination key
        build[destKey] = value;
    }
    return build;
}

Live-Beispiel:

"use strict";
var input = {
    "id":"1",
    "ch":[
        {
            "id":"3",
            "ch":[
            ],
            "d":{
                "u":"3",
                "tz":"8.00"
            }
        },
        {
            "id":"45",
            "ch":[
                {
                    "id":"70",
                    "ch":[
                        {
                            "id":"43",
                            "ch":[
                            ],
                            "d":{
                                "u":"43",
                                "tz":"-7.00"
                            }
                        }
                    ],
                    "d":{
                        "u":"70",
                        "tz":"-7.00"
                    }
                }
            ],
            "d":{
                "u":"45",
                "tz":"-7.00"
            }
        }
    ],
    "d":{
        "u":"1",
        "tz":"8.00"
    }
};

var keys_short = ["ch","d","u","tz"];
var keys_long = ["children","data","user_id","time_zone"];
function refit_keys(o){
    var build, key, destKey, ix, value;

    // Only handle non-null objects
    if (o === null || typeof o !== "object") {
        return o;
    }

    // Handle array just by handling their contents
    if (Array.isArray(o)) {
        return o.map(refit_keys);
    }

    // We have a non-array object
    build = {};
    for (key in o) {
        // Get the destination key
        ix = keys_short.indexOf(key);
        destKey = ix === -1 ? key : keys_long[ix];

        // Get the value
        value = o[key];

        // If this is an object, recurse
        if (typeof value === "object") {
            value = refit_keys(value);
        }

        // Set it on the result using the destination key
        build[destKey] = value;
    }
    return build;
}

console.log(refit_keys(input));
.as-console-wrapper {
    max-height: 100% !important;
}

Aber anstelle von parallelen Arrays würde ich vorschlagen, ein Mapping über ein Objekt oder a . zu verwenden Map:

// Object with no prototype to avoid false matches on `toString` and other built-ins
var mapShortToLong = Object.assign(Object.create(null), {
    "ch": "children",
    "d":  "data",
    "u":  "user_id",
    "tz": "time_zone"
});
function refit_keys(o){
    var build, key, destKey, value;

    // Only handle non-null objects
    if (o === null || typeof o !== "object") {
        return o;
    }

    // Handle array just by handling their contents
    if (Array.isArray(o)) {
        return o.map(refit_keys);
    }

    build = {};
    for (key in o) {
        // Get the destination key
        destKey = mapShortToLong[key] || key;

        // Get the value
        value = o[key];

        // If this is an object, recurse
        if (typeof value === "object") {
            value = refit_keys(value);
        }

        // Set it on the result using the destination key
        build[destKey] = value;
    }
    return build;
}

Live-Beispiel:

"use strict";
var input = {
    "id":"1",
    "ch":[
        {
            "id":"3",
            "ch":[
            ],
            "d":{
                "u":"3",
                "tz":"8.00"
            }
        },
        {
            "id":"45",
            "ch":[
                {
                    "id":"70",
                    "ch":[
                        {
                            "id":"43",
                            "ch":[
                            ],
                            "d":{
                                "u":"43",
                                "tz":"-7.00"
                            }
                        }
                    ],
                    "d":{
                        "u":"70",
                        "tz":"-7.00"
                    }
                }
            ],
            "d":{
                "u":"45",
                "tz":"-7.00"
            }
        }
    ],
    "d":{
        "u":"1",
        "tz":"8.00"
    }
};

// Object with no prototype to avoid false matches on `toString` and other built-ins
var mapShortToLong = Object.assign(Object.create(null), {
    "ch": "children",
    "d":  "data",
    "u":  "user_id",
    "tz": "time_zone"
});
function refit_keys(o){
    var build, key, destKey, value;

    // Only handle non-null objects
    if (o === null || typeof o !== "object") {
        return o;
    }

    // Handle array just by handling their contents
    if (Array.isArray(o)) {
        return o.map(refit_keys);
    }

    build = {};
    for (key in o) {
        // Get the destination key
        destKey = mapShortToLong[key] || key;

        // Get the value
        value = o[key];

        // If this is an object, recurse
        if (typeof value === "object") {
            value = refit_keys(value);
        }

        // Set it on the result using the destination key
        build[destKey] = value;
    }
    return build;
}

console.log(refit_keys(input));
.as-console-wrapper {
    max-height: 100% !important;
}

Oder in modernem JavaScript:

// Using a `Map` here to provide a `Map` example, but you can ue an object as
// in the previous ones if you prefer if the keys are strings
const mapShortToLong = new Map([
    ["ch", "children"],
    ["d",  "data"],
    ["u",  "user_id"],
    ["tz", "time_zone"],
]);
function refit_keys(o){
    // Only handle non-null objects
    if (o === null || typeof o !== "object") {
        return o;
    }

    // Handle array just by handling their contents
    if (Array.isArray(o)) {
        return o.map(refit_keys);
    }

    const build = {};
    for (const key in o) {
        // Get the destination key
        const destKey = mapShortToLong.get(key) || key;

        // Get the value
        let value = o[key];

        // If this is an object, recurse
        if (typeof value === "object") {
            value = refit_keys(value);
        }

        // Set it on the result using the destination key
        build[destKey] = value;
    }
    return build;
}

Live-Beispiel:

"use strict";
var input = {
    "id":"1",
    "ch":[
        {
            "id":"3",
            "ch":[
            ],
            "d":{
                "u":"3",
                "tz":"8.00"
            }
        },
        {
            "id":"45",
            "ch":[
                {
                    "id":"70",
                    "ch":[
                        {
                            "id":"43",
                            "ch":[
                            ],
                            "d":{
                                "u":"43",
                                "tz":"-7.00"
                            }
                        }
                    ],
                    "d":{
                        "u":"70",
                        "tz":"-7.00"
                    }
                }
            ],
            "d":{
                "u":"45",
                "tz":"-7.00"
            }
        }
    ],
    "d":{
        "u":"1",
        "tz":"8.00"
    }
};

// Using a `Map` here to provide a `Map` example, but you can ue an object as
// in the previous ones if you prefer if the keys are strings
const mapShortToLong = new Map([
    ["ch", "children"],
    ["d",  "data"],
    ["u",  "user_id"],
    ["tz", "time_zone"],
]);
function refit_keys(o){
    // Only handle non-null objects
    if (o === null || typeof o !== "object") {
        return o;
    }

    // Handle array just by handling their contents
    if (Array.isArray(o)) {
        return o.map(refit_keys);
    }

    const build = {};
    for (const key in o) {
        // Get the destination key
        const destKey = mapShortToLong.get(key) || key;

        // Get the value
        let value = o[key];

        // If this is an object, recurse
        if (typeof value === "object") {
            value = refit_keys(value);
        }

        // Set it on the result using the destination key
        build[destKey] = value;
    }
    return build;
}

console.log(refit_keys(input));
.as-console-wrapper {
    max-height: 100% !important;
}

  • Darüber hinaus. Funktioniert einwandfrei, hat mir etwas beigebracht und eine bessere Methode gefunden

    – Andy Gee

    3. November ’13 um 11:55


  • Irgendein Beweis dafür, dass die Seconf-Methode besser/schneller ist?

    – Ben Orozco

    7. November ’14 um 17:07

  • @benoror: Ich glaube nicht, dass ich behauptet habe, es sei besser oder schneller, aber parallele Arrays sind im Allgemeinen ein Wartungsproblem. Zu einfach, das eine zu ändern und das andere nicht. Viel schwieriger irrtümlich zu modifizieren halb eines Eigenschaftsinitialisierers. 😉

    – TJ Crowder

    7. November ’14 um 17:10


  • @PanMan – Danke! Ich habe das behoben und allgemein ein wenig aktualisiert.

    – TJ Crowder

    6. April ’21 um 10:55

Objektschlussel rekursiv umbenennen
Bogdan D

Etwas spät, aber ich war auf der Suche nach einer schönen kurzen Umsetzung, die auch beschäftigt sich mit Arrays (die vorherige Antwort nicht), also habe ich beschlossen, meine generische ES6-Implementierung zu veröffentlichen, da sie einigen Leuten helfen kann:

function deepMapKeys(originalObject, callback) {
  if (typeof originalObject !== 'object') {
    return originalObject
  }

  return Object.keys(originalObject || {}).reduce((newObject, key) => {
    const newKey = callback(key)
    const originalValue = originalObject[key]
    let newValue = originalValue
    if (Array.isArray(originalValue)) {
      newValue = originalValue.map(item => deepMapKeys(item, callback))
    } else if (typeof originalValue === 'object') {
      newValue = deepMapKeys(originalValue, callback)
    }
    return {
      ...newObject,
      [newKey]: newValue,
    }
  }, {})
}

Für den fraglichen Fall lautet der Aufruf:

deepMapKeys(inputObject, key => (keys_long[keys_short.indexOf(key)] || key))

Davon abgesehen, wenn Sie npm verwenden können, gibt es mehrere Pakete (hier ist eins, Ein weiterer..)

  • Danke für die Links zu den Paketen.

    – Mansoorkhan Cherupuzha

    15. Januar ’21 um 6:43

1641748259 790 Objektschlussel rekursiv umbenennen
musikalisch_ut

Eines der Probleme könnte sein, dass die Variable build ist eigentlich eine globale Variable. Es enthält daher nur das Ergebnis der ersten Tiefe der Rekursion.

a . hinzufügen var Vor build sollte einen Teil des Problems lösen.

  • Nein, das ist nicht das einzige Problem. Es ist ein problem, es ist nur nicht das einzige.

    – TJ Crowder

    3. November ’13 um 11:45

Prägnantere Implementierung der rekursiven Abbildungsfunktion für Objektschlüssel:

const objectRecursiveKeyMap = (obj, fn) =>
  Object.fromEntries(Object.entries(obj).map(([key, value]) => {
    const getValue = v =>
      (typeof v === 'object' && v !== null) ? objectRecursiveKeyMap(v, fn) : v

    return [fn(key), Array.isArray(value)
      ? value.map(val => getValue(val))
      : getValue(value)]
  }))

Beispiel verwenden:

objectRecursiveKeyMap(obj, key => key.toUpperCase())

1641748259 736 Objektschlussel rekursiv umbenennen
Chris H.

Ich mag diesen Ansatz. Aber ich bin darüber gestolpert:

du nennst es so: deepMapKeys({testValue:["justString"]}, key => (key));

returnValue enthält:

{0: "j", 1: "u", 2: "s", 3: "t", 4: "S", 5: "t", 6: "r", 7: "i", 8: "n", 9: "g"}

Länge: 1

Will sagen, es konvertiert meine Zeichenfolge in ein Array.

  • danke für das Feedback @Chris H. , ich habe die Antwort aktualisiert, um den Anwendungsfall zu beheben. Sie sollten meine Antwort einfach direkt kommentieren, da dies keine Antwort auf die Frage ist und daher verwirrend ist. Außerdem erhalte ich keine Benachrichtigung (ich habe Ihr Feedback zufällig bemerkt), es sei denn, Sie kommentieren die Antwort. Beifall

    – Bogdan D

    23. April ’19 um 15:25


  • danke für das Feedback @Chris H. , ich habe die Antwort aktualisiert, um den Anwendungsfall zu beheben. Sie sollten meine Antwort einfach direkt kommentieren, da dies keine Antwort auf die Frage ist und daher verwirrend ist. Außerdem erhalte ich keine Benachrichtigung (ich habe Ihr Feedback zufällig bemerkt), es sei denn, Sie kommentieren die Antwort. Beifall

    – Bogdan D

    23. April ’19 um 15:25


.

227860cookie-checkObjektschlüssel rekursiv umbenennen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy