繁体   English   中英

如何使用 JavaScript (lodash) 深入 map object 键?

[英]How to deeply map object keys with JavaScript (lodash)?

https://lodash.com/docs#mapKeys

是否可以使用 Lodash 深入 map 对象的键? 如果没有,是否有另一个库提供此功能(如果与其他深度迭代和操作功能组合在一起,甚至更好?),否则? go 如何实现这一点,我看到的主要困难是识别安全的纯键/值对象。 deeply iterable,抛出 Arrays 很容易,但需要注意的是 function 不应该像正则表达式那样尝试对其他对象进行深度迭代。 例如。

预期结果-

var obj = { a: 2, b: { c: 2, d: { a: 3 } } };
_.deepMapKeys(obj, function (val, key) {
  return key + '_hi';
});
// => { a_hi: 2, b_hi: { c_hi: 2, d_hi: { a_hi: 3 } } }

以下是你在lodash如何做到这lodash

_.mixin({
    'deepMapKeys': function (obj, fn) {

        var x = {};

        _.forOwn(obj, function(v, k) {
            if(_.isPlainObject(v))
                v = _.deepMapKeys(v, fn);
            x[fn(v, k)] = v;
        });

        return x;
    }
});

这是一个更抽象的mixin,递归地应用任何给定的映射器:

_.mixin({
    deep: function (obj, mapper) {
        return mapper(_.mapValues(obj, function (v) {
            return _.isPlainObject(v) ? _.deep(v, mapper) : v;
        }));
    },
});

用法(返回与上面相同):

obj = _.deep(obj, function(x) {
    return _.mapKeys(x, function (val, key) {
        return key + '_hi';
    });
});

另一种选择,具有更优雅的语法:

_.mixin({
    deeply: function (map) {
        return function(obj, fn) {
            return map(_.mapValues(obj, function (v) {
                return _.isPlainObject(v) ? _.deeply(map)(v, fn) : v;
            }), fn);
        }
    },
});


obj = _.deeply(_.mapKeys)(obj, function (val, key) {
    return key + '_hi';
});

在扩展georg的答案时,这就是我正在使用的内容。 这种扩展的mixin也增加了在对象内映射对象数组的能力,这是一个简单但重要的变化。

_.mixin({
    deeply: function (map) {
      return function (obj, fn) {
        return map(_.mapValues(obj, function (v) {
          return _.isPlainObject(v) ? _.deeply(map)(v, fn) : _.isArray(v) ? v.map(function(x) {
            return _.deeply(map)(x, fn);
          }) : v;
        }), fn);
      }
    },
  });

编辑:这将映射对象值,而不是其键。 我误解了这个问题。


function deepMap (obj, cb) {
    var out = {};

    Object.keys(obj).forEach(function (k) {
      var val;

      if (obj[k] !== null && typeof obj[k] === 'object') {
        val = deepMap(obj[k], cb);
      } else {
        val = cb(obj[k], k);
      }

      out[k] = val;
    });

  return out;
}

并用它作为

var lol = deepMap(test, function (v, k) {
    return v + '_hi';
});

它将递归迭代对象拥有的可枚举属性,并调用CB传递当前值和键。 返回的值将替换新对象的现有值。 它不会改变原始对象。

请参阅小提琴: https//jsfiddle.net/1veppve1/

我从Chris Jones的答案中添加了一点改进。

下面的代码修复了一些Array元素的意外结果。

_.mixin({
  deeply: function (map) {
    var deeplyArray = function (obj, fn) {
      return obj.map(function(x) {
        return _.isPlainObject(x) ? _.deeply(map)(x, fn) : x;
      })
    }

    return function (obj, fn) {
      if (_.isArray(obj)) {
        return deeplyArray(obj, fn);
      }

      return map(_.mapValues(obj, function (v) {
        return _.isPlainObject(v) ? _.deeply(map)(v, fn) : _.isArray(v) ? 
          deeplyArray(v, fn) : v;
      }), fn);
    }
  },
});

根据性能效率不是最好的,但是如果你想从你身边跳过递归部分并希望保持代码清洁和简单,那么你可以将它JSON.parse json并使用JSON.parse和附加参数(回调)并在那里你可以使用lodash转换密钥。

JSON.parse(JSON.stringify(obj), (k, v) => _.isObject(v) ? _.mapKeys(v, (_v, _k) => _k + '_hi') : v)

这是一个工作示例:

 let obj = { a: 2, b: { c: 2, d: { a: 3 } } }; let mappedObj = JSON.parse(JSON.stringify(obj), (k, v) => _.isObject(v) ? _.mapKeys(v, (_v, _k) => _k + '_hi') : v) console.log(mappedObj) 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script> 

接受的解决方案不适用于更深层次的数组/对象/简单类型或 arrays 之类的简单类型(字符串/数字)

{
  "notification-type": 1,
  "reciept_my": {
    "latest__info": [
      {
        "a-a": 1,
        "reciept_my": { "latest__info": [{ "a-a": 1 }, "b", true, "d"] }
      },
      "b",
      true,
      "d"
    ]
  }
}

例如['s']转换为Object {0: "s"}

这是使其工作的改进:

function deepMapKeys(obj, fn) {
  if (!_.isArray(obj) && !_.isPlainObject(obj)) {
    return obj;
  }

  const x = _.isArray(obj) ? [] : {};

  _.forOwn(obj, function (v, k) {
    if (_.isArray(v)) {
      v = v.map((v) => deepMapKeys(v, fn));
    }
    if (_.isPlainObject(v)) {
      v = deepMapKeys(v, fn);
    }
    x[fn(k)] = v;
  });

  return x;
}

Typescript

这是georg 的答案的打字版本。

小心,如果你不直接导入它,它会抛出“deeply is not a function”错误——你需要在你的代码调用_.deeply之前导入(或编写)这个 mixin。

import _, { Dictionary, ObjectIterator } from "lodash"

declare module "lodash" {
  interface LoDashStatic {
    deeply<T extends object, TResult>(map: unknown): (obj: T | null | undefined, callback: ObjectIterator<T, TResult>) => { [P in keyof T]: TResult }
  }
}

_.mixin({
  deeply: (map) => {
    return (object: Dictionary<unknown>, callback: ObjectIterator<object, unknown>) => {
      return map(_.mapValues(object, value => {
        return _.isPlainObject(value) ? _.deeply(map)(value as object, callback) : value
      }), callback)
    }
  },
})

export default {}

我的实现

/**
 * https://stackoverflow.com/questions/38304401/javascript-check-if-dictionary/71975382#71975382
 */
export function isDictionary(object: unknown): object is Record<keyof never, unknown> {
  return object instanceof Object && object.constructor === Object
}

/**
 * https://stackoverflow.com/a/75010148/12468111
 */
export function mapKeysDeep(object: Record<keyof never, unknown>, callback: (key: string, value: unknown) => keyof never): Record<string, unknown> {
  function iterate(value: unknown): unknown {
    if (isDictionary(value)) {
      return mapKeysDeep(value, callback)
    }

    if (value instanceof Array) {
      return value.map(iterate)
    }

    return value
  }

  return (
    Object
      .entries(object)
      .reduce((result, [key, value]) => ({ ...result, [callback(key, value)]: iterate(value) }), {})
  )
}

不要忘记放置指向您复制粘贴的代码的链接(请)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM