admin管理员组

文章数量:1406937

I am trying to figure out how to use recursion to replace key names of an object with a new key name (and this includes key names inside of nested objects as well). I feel it has something to with the way I'm reassigning to newObj in my first if conditional statement. Any suggestions? Here is my code so far:

// 24. Find all keys in an object (and nested objects) by a provided name and rename
// them to a provided new name while preserving the value stored at that key.

const replaceKeysInObj = (obj, oldKey, newKey, newObj = {}) => {
 for(let key in obj){
   if (key === oldKey){
     newObj[newKey] = obj[key]    
   } 
   if (typeof obj[key] === 'object'){
     replaceKeysInObj(obj[key], oldKey, newKey);
   }
   else {
     newObj[oldKey] = obj[key]
   }
 }
   return newObj
}


var obj = {'e':{'e':'y'},'l': 'l','y':'e'};
console.log(replaceKeysInObj(obj, 'e', 'new')) 

I am trying to figure out how to use recursion to replace key names of an object with a new key name (and this includes key names inside of nested objects as well). I feel it has something to with the way I'm reassigning to newObj in my first if conditional statement. Any suggestions? Here is my code so far:

// 24. Find all keys in an object (and nested objects) by a provided name and rename
// them to a provided new name while preserving the value stored at that key.

const replaceKeysInObj = (obj, oldKey, newKey, newObj = {}) => {
 for(let key in obj){
   if (key === oldKey){
     newObj[newKey] = obj[key]    
   } 
   if (typeof obj[key] === 'object'){
     replaceKeysInObj(obj[key], oldKey, newKey);
   }
   else {
     newObj[oldKey] = obj[key]
   }
 }
   return newObj
}


var obj = {'e':{'e':'y'},'l': 'l','y':'e'};
console.log(replaceKeysInObj(obj, 'e', 'new')) 
Share Improve this question asked Jul 27, 2020 at 6:02 fastandthecuriousfastandthecurious 391 silver badge7 bronze badges
Add a ment  | 

6 Answers 6

Reset to default 4

With some modifications to your approach

const replaceKeysInObj = (obj, oldKey, newKey, newObj = {}) => {
 if (typeof obj !== "object") return obj; 
 for (let key in obj) {
    newObj[key === oldKey ? newKey : key] = replaceKeysInObj(obj[key], oldKey, newKey);
 }
  return newObj;
};

const obj = { e: { e: "y" }, l: "l", y: "e" };
console.log(replaceKeysInObj(obj, "e", "new"));

const obj2 = { e: { e: "y" }, l: { e: "y" }, y: "e" };
console.log(replaceKeysInObj(obj2, "e", "new"));

Try this function:

function replaceKeysInObj(obj, oldKey, newKey) {
  Object.keys(obj).map((key) => {
    if(typeof obj[key] === 'object') {
      replaceKeysInObj(obj[key], oldKey, newKey);
    }
    if(key === oldKey) {
      obj[newKey] = obj[oldKey]
      delete obj[oldKey];
    }
  });

  return obj;
}

let obj = {'e':{'e':'y'},'l': 'l','y':'e'};
console.log(replaceKeysInObj(obj, 'e', 'new')) 

If we think of this a little more generally, we can write a simple recursion. We can write a function to replace all the keys in an arbitrarily-nested object with the result of calling a function on the current keys. We could use this in various ways. If we wanted to convert all keys to upper-case, we would pass it k => k.toUpperCase(). Or for your case, we could write something like k => k == oldKey ? newKey : k. One implementation of this idea could look like this:

const replaceKey = (f) => (o) =>
  Array .isArray (o) 
    ? o .map (replaceKey (f))
  : Object (o) === o
    ? Object .fromEntries (Object .entries (o) .map (([k, v]) => [f(k), replaceKey (f) (v)]))
    : o

const replaceKeysInObj = (oldKey, newKey) =>
  replaceKey (k => k == oldKey ? newKey : k)

const testCase = {foo: 1, bar: {baz: 2, qux: {corge: [{baz: 3}, {baz: 4}]}}}

console.log (
  replaceKey (k => k.toUpperCase()) (testCase)
) //~> {FOO: 1, BAR: {BAZ: 2, QUX: {CORGE: [{BAZ: 3}, {BAZ: 4}]}}}

console.log (
  replaceKeysInObj ('baz', 'grault') (testCase)
) //~> {foo: 1, bar: {grault: 2, qux: {corge: [{grault: 3}, {grault: 4}]}}}
.as-console-wrapper {max-height: 100% !important; top: 0}

Note that I changed the API of your function a bit. If you wanted the original signature, we could just write

const replaceKeysInObj = (obj, oldKey, newKey) =>
  replaceKey (k => k == oldKey ? newKey : k) (obj)

But there is an advantage to how I wrote it, one that I take advantage of often. It lets us partially apply the oldKey and newKey to get a reusable function

const e2new = replaceKeysInObj ('e', 'new')

// later

e2new ({e: {e: 'y'}, l: 'l', y: 'e'}) //=> {new: {new: "y"}, l: "l", y:"e"}

But there's a general point here worth noting: it's often simpler to abstract at least a bit from our current problem, writing a more general solution that is configured with a function or two to fill in the details. Even if we eventually give up the abstraction and inline those configuration functions, it can help us see the problem more clearly.

if you want to change object keys name i think this is working !

if (oldKey !== newKey) {

  Object.defineProperty(obj, newKey, Object.getOwnPropertyDescriptor(obj, oldKey));

  delete o[oldKey];

}

If you wish to return a new object with the replaced keys rather than mutating the object, as per the code you have posted, change it to the following:

const replaceKeysInObj = (obj, oldKey, newKey, newObj = {}) => {
  for (let key in obj) {
    if (key === oldKey) {
      newObj[newKey] = obj[key];
    } else {
      newObj[key] = obj[key];
    }
    if (typeof obj[key] === 'object') {
      newObj[newKey] = replaceKeysInObj(obj[key], oldKey, newKey);
    }
  }
  return newObj;
};

var obj = {
  'e': {
    'e': 'y',
  },
  'l': 'l',
  'y': 'e',
};

console.log(replaceKeysInObj(obj, 'e', 'new'));
// { new: { new: 'y' }, l: 'l', y: 'e' }

Based on answer of @Scott Sauyet I made one function. You can see example on CodeSandbox. Link for CodeSandbox.

export const replaceKeysInObj = (data, oldKey, newKey) => {
  const replaceKey = (f) => (newdata) => {
    if (Array.isArray(newdata)) return newdata.map(replaceKey(f));
    if (Object(newdata) === newdata) {
      return Object.fromEntries(
        Object.entries(newdata).map(([key, value]) => [
          f(key),
          replaceKey(f)(value)
        ])
      );
    }
    return data;
  };
  return replaceKey((key) => (key === oldKey ? newKey : key))(data);
};

本文标签: javascriptHow can I recursively replace the key name in an objectStack Overflow