簡體   English   中英

遞歸重命名對象鍵

[英]Renaming object keys recursively

我有一個遞歸函數來重命名對象的鍵名,但我無法弄清楚如何重命名其中的 2 個鍵(問題鍵是對象)

我認為問題在於我在哪里檢查對象類型,但此時如何重命名密鑰?

實際的數組非常大,但下面是一個精簡版。

任何幫助表示贊賞。

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

我的輸入如下所示:

{
    "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"
    }
}

我的輸出是這樣的:

{
    "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"
    }
}

那里有幾個問題。

一是您因為未能在函數中聲明您的build變量而成為隱式全局變量的犧牲品。

但邏輯也有問題,這里有一個最小的返工:

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

現場示例:

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

但不是並行數組,我建議使用映射,通過對象或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;
}

現場示例:

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

或者在現代 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;
}

現場示例:

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

有點晚了,但我正在尋找一個很好的簡短實現,它也處理數組(前面的答案沒有),所以我決定發布我的通用 ES6 實現,因為它可能對某些人有所幫助:

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,
    }
  }, {})
}

對於有問題的案例,調用將是:

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

話雖如此,如果您可以使用 npm,那么有幾個包(這里是一個另一個..)

問題之一可能是變量build實際上是一個全局變量。 因此,它只包含遞歸中第一個深度的結果。

build之前添加一個var應該可以解決部分問題。

我喜歡這種方法。 但我偶然發現了這一點:

你這樣稱呼它: deepMapKeys({testValue:["justString"]}, key => (key));

返回值包含:

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

長度:1

會說,它將我的字符串轉換為數組。

對象鍵遞歸映射函數的更簡潔實現:

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)]
  }))

使用示例:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM