【问题标题】:How to gather nested object keys to an array?如何将嵌套对象键收集到数组中?
【发布时间】:2022-01-12 07:46:08
【问题描述】:

如何将对象键转换为具有不同数据类型的数组? Javascript map 函数不覆盖对象数据类型值。



示例:

let obj = {
  data1: 'test',
  data2: boolean,
  data3: {
    test1: 'test',
    test2: 'test'
  }
}

预期输出:

let arr = [
  'data1',
  'data2',
  'data3.test1',
  'data3.test2'
]

【问题讨论】:

  • 你试过Object.keys(obj)吗?

标签: javascript arrays object


【解决方案1】:

const listPaths = (obj) => {
  function rKeys(o, path) {
    if (typeof o !== "object") return path;
    return Object.keys(o).map((key) =>
      rKeys(o[key], path ? [path, key].join(".") : key)
    );
  }

  return rKeys(obj).toString().split(",").filter(Boolean);
}

const obj = {
  data1: 'test',
  data2: false,
  data3: {
    test1: 'test',
    test2: 'test'
  }
};

console.log(listPaths(obj));

【讨论】:

    【解决方案2】:

    另一个可能的选择是创建一个函数transform 来获取对象的条目(对象的[[key, val], ...] 数组),如果value 不是,则将这些条目中的每一个映射到它的key t 一个对象,否则,如果该值是一个对象,您可以在内部对象上再次调用 transform 函数,这将再次返回一个键数组。然后,您可以在此键数组上使用 .map() 将当前键(保存对象)作为前缀添加到内部对象中的键:

    const obj = {
      data1: 'test',
      data2: true,
      data3: {
        test1: 'test',
        test2: {
          example1: 0
        },
        test3: 'test'
      }
    };
    
    const transform = (obj) => {
      return Object.entries(obj).flatMap(([key, val]) => 
        Object(val) === val ? transform(val).map(subKey => `${key}.${subKey}`) : key
      );
    }
    
    console.log(transform(obj));

    【讨论】:

      【解决方案3】:

      这是一种达到深层属性的递归方法。如果有些东西很难理解,请随时提出问题。

      const isArray = hit => Array.isArray(hit)
      const isObject = hit => !isArray(hit) && typeof hit === 'object'
      const isNonIterable = hit => !isArray(hit) && !isObject(hit)
      
      const toPath = (data, prefix = '') => {
        const store = []
      
        if (isArray(data)) {
          if (prefix) {
            store.push(prefix)
          }
      
          store.push(...toPath(data[0], `${prefix}[i]`))
          return store
        }
      
        if (isObject(data)) {
          if (prefix) {
            store.push(prefix)
          }
      
          for (const key in data) {
            const currData = data[key]
            const currPrefix = prefix ? `${prefix}.${key}` : key
      
            if (isNonIterable(currData)) {
              store.push(currPrefix)
            } else {
              store.push(...toPath(currData, currPrefix))
            }
          }
      
          return store
        }
      
        return store
      }
      
      
      const data = {
        match: {
          id: 720359,
          play: '2021-12-20 00:30:00',
          score: null,
          status: 'Postponed'
        },
        league: {
          id: 1115,
          kor: '',
          name: 'Norway: Blno'
        },
        home_team: {
          id: 1610,
          kor: '',
          name: 'Tromso'
        },
        away_team: {
          id: 1613,
          kor: '',
          name: 'Avangard Omsk'
        },
        game: {
          id: 3,
          kor: '농구',
          name: 'basketball'
        },
        match_games: [
          {
            type: {
              id: 1,
              div: 'odd',
              kor: '승/무/패',
              name: '3Way Result'
            },
            odds: {
              odd: {
                size: 1,
                Home: 2.95,
                deep: 1,
                stop: 0,
                gap: 1.45,
                Draw: 13,
                Away: 1.5
              }
            },
            score: '[83,60]'
          }
        ]
      }
      
      const paths = toPath(data)
      
      console.log(paths)
      
      // [
      //   '[i]',
      //   '[i].match',
      //   '[i].match.id',
      //   '[i].match.play',
      //   '[i].match.score',
      //   '[i].match.status',
      //   '[i].league',
      //   '[i].league.id',
      //   '[i].league.kor',
      //   '[i].league.name',
      //   '[i].home_team',
      //   '[i].home_team.id',
      //   '[i].home_team.kor',
      //   '[i].home_team.name',
      //   '[i].away_team',
      //   '[i].away_team.id',
      //   '[i].away_team.kor',
      //   '[i].away_team.name',
      //   '[i].game',
      //   '[i].game.id',
      //   '[i].game.kor',
      //   '[i].game.name',
      //   '[i].match_games',
      //   '[i].match_games[i]',
      //   '[i].match_games[i].type',
      //   '[i].match_games[i].type.id',
      //   '[i].match_games[i].type.div',
      //   '[i].match_games[i].type.kor',
      //   '[i].match_games[i].type.name',
      //   '[i].match_games[i].odds',
      //   '[i].match_games[i].odds.odd',
      //   '[i].match_games[i].odds.odd.size',
      //   '[i].match_games[i].odds.odd.Home',
      //   '[i].match_games[i].odds.odd.deep',
      //   '[i].match_games[i].odds.odd.stop',
      //   '[i].match_games[i].odds.odd.gap',
      //   '[i].match_games[i].odds.odd.Draw',
      //   '[i].match_games[i].odds.odd.Away',
      //   '[i].match_games[i].score'
      // ]

      此外,您只需稍微调整代码即可添加数据类型:

      const isArray = hit => Array.isArray(hit)
      const isObject = hit => !isArray(hit) && typeof hit === 'object'
      const isNonIterable = hit => !isArray(hit) && !isObject(hit)
      const isBoolean = hit => typeof hit === 'boolean'
      const isNumber = hit => typeof hit === 'number' || (!isNaN(Number(hit)) && !isBoolean(hit))
      const isString = hit => typeof hit === 'string'
      const isDate = hit => new Date(hit).toString() !== 'Invalid Date'
      
      const getType = payload => {
        if (isArray(payload)) {
          return 'array'
        }
      
        if (isObject(payload)) {
          return 'object'
        }
      
        if (isNumber(payload)) {
          return 'number'
        }
      
        if (isDate(payload)) {
          return 'date'
        }
      
        if (isString(payload)) {
          return 'string'
        }
      
        if (isBoolean(payload)) {
          return 'boolean'
        }
      
        if (isBoolean(payload)) {
          return 'boolean'
        }
      }
      
      const toPath = (data, prefix = '') => {
        const store = []
      
        const storeData = (loggerPayload, loggerPrefix) => ({
          path: loggerPrefix,
          type: getType(loggerPayload)
        })
      
        if (isArray(data)) {
          if (prefix) {
            store.push(storeData(data, prefix))
          }
      
          store.push(...toPath(data[0], `${prefix}[i]`))
          return store
        }
      
        if (isObject(data)) {
          if (prefix) {
            store.push(storeData(data, prefix))
          }
      
          for (const key in data) {
            const currData = data[key]
            const currPrefix = prefix ? `${prefix}.${key}` : key
      
            isNonIterable(currData)
              ? store.push(storeData(currData, currPrefix))
              : store.push(...toPath(currData, currPrefix))
          }
      
          return store
        }
      
        return store
      }
      
      const data = [
        {
          match: {
            id: 720359,
            play: '2021-12-20 00:30:00',
            score: null,
            status: 'Postponed'
          },
          league: {
            id: 1115,
            kor: '',
            name: 'Norway: Blno'
          },
          home_team: {
            id: 1610,
            kor: '',
            name: 'Tromso'
          },
          away_team: {
            id: 1613,
            kor: '',
            name: 'Avangard Omsk'
          },
          game: {
            id: 3,
            kor: '농구',
            name: 'basketball'
          },
          match_games: [
            {
              type: {
                id: 1,
                div: 'odd',
                kor: '승/무/패',
                name: '3Way Result'
              },
              odds: {
                odd: {
                  size: 1,
                  Home: 2.95,
                  deep: 1,
                  stop: 0,
                  gap: 1.45,
                  Draw: 13,
                  Away: 1.5
                }
              },
              score: '[83,60]'
            }
          ]
        }
      ]
      
      const paths = toPath(data)
      
      console.log(paths)
      
      // [
      //   {
      //     "path": "[i]",
      //     "type": "object"
      //   },
      //   {
      //     "path": "[i].match",
      //     "type": "object"
      //   },
      //   {
      //     "path": "[i].match.id",
      //     "type": "number"
      //   },
      //   {
      //     "path": "[i].match.play",
      //     "type": "date"
      //   },
      //   {
      //     "path": "[i].match.score",
      //     "type": "object"
      //   },
      //   {
      //     "path": "[i].match.status",
      //     "type": "string"
      //   },
      //   {
      //     "path": "[i].league",
      //     "type": "object"
      //   },
      //   {
      //     "path": "[i].league.id",
      //     "type": "number"
      //   },
      //   {
      //     "path": "[i].league.kor",
      //     "type": "number"
      //   },
      //   {
      //     "path": "[i].league.name",
      //     "type": "string"
      //   },
      //   {
      //     "path": "[i].home_team",
      //     "type": "object"
      //   },
      //   {
      //     "path": "[i].home_team.id",
      //     "type": "number"
      //   },
      //   {
      //     "path": "[i].home_team.kor",
      //     "type": "number"
      //   },
      //   {
      //     "path": "[i].home_team.name",
      //     "type": "string"
      //   },
      //   {
      //     "path": "[i].away_team",
      //     "type": "object"
      //   },
      //   {
      //     "path": "[i].away_team.id",
      //     "type": "number"
      //   },
      //   {
      //     "path": "[i].away_team.kor",
      //     "type": "number"
      //   },
      //   {
      //     "path": "[i].away_team.name",
      //     "type": "string"
      //   },
      //   {
      //     "path": "[i].game",
      //     "type": "object"
      //   },
      //   {
      //     "path": "[i].game.id",
      //     "type": "number"
      //   },
      //   {
      //     "path": "[i].game.kor",
      //     "type": "string"
      //   },
      //   {
      //     "path": "[i].game.name",
      //     "type": "string"
      //   },
      //   {
      //     "path": "[i].match_games",
      //     "type": "array"
      //   },
      //   {
      //     "path": "[i].match_games[i]",
      //     "type": "object"
      //   },
      //   {
      //     "path": "[i].match_games[i].type",
      //     "type": "object"
      //   },
      //   {
      //     "path": "[i].match_games[i].type.id",
      //     "type": "number"
      //   },
      //   {
      //     "path": "[i].match_games[i].type.div",
      //     "type": "string"
      //   },
      //   {
      //     "path": "[i].match_games[i].type.kor",
      //     "type": "string"
      //   },
      //   {
      //     "path": "[i].match_games[i].type.name",
      //     "type": "string"
      //   },
      //   {
      //     "path": "[i].match_games[i].odds",
      //     "type": "object"
      //   },
      //   {
      //     "path": "[i].match_games[i].odds.odd",
      //     "type": "object"
      //   },
      //   {
      //     "path": "[i].match_games[i].odds.odd.size",
      //     "type": "number"
      //   },
      //   {
      //     "path": "[i].match_games[i].odds.odd.Home",
      //     "type": "number"
      //   },
      //   {
      //     "path": "[i].match_games[i].odds.odd.deep",
      //     "type": "number"
      //   },
      //   {
      //     "path": "[i].match_games[i].odds.odd.stop",
      //     "type": "number"
      //   },
      //   {
      //     "path": "[i].match_games[i].odds.odd.gap",
      //     "type": "number"
      //   },
      //   {
      //     "path": "[i].match_games[i].odds.odd.Draw",
      //     "type": "number"
      //   },
      //   {
      //     "path": "[i].match_games[i].odds.odd.Away",
      //     "type": "number"
      //   },
      //   {
      //     "path": "[i].match_games[i].score",
      //     "type": "string"
      //   }
      // ]

      【讨论】:

        【解决方案4】:

        我建议创建一个函数,比如getKeys(),它将递归地遍历对象,一旦命中每个叶子项,就会以“a.b.c”的形式返回键。

        let obj = {
          data1: 'test',
          data2: true,
          data3: {
            test1: 'test',
            test2: 'test'
          }
        }
        
        function getKeys(obj, path = []) {
            let keys = [];
            // We've hit a 'leaf' in the object tree, return the path.
            if (!obj || typeof(obj) !== 'object') return [ path.join('.') ];
            // Call recursively for each child object...
            for(let k in obj) {
                keys = [...keys, ...getKeys(obj[k], [...path, k])];
            } 
            return keys;
        }
        
        console.log(getKeys(obj))
            
        .as-console-wrapper { max-height: 100% !important; top: 0; }

        【讨论】:

          【解决方案5】:

          创建一个递归函数来获取对象的条目,并使用Array.flatMap() 对其进行迭代。将当前键连接到前一个键。如果当前值是一个对象,则再次调用该函数,并传递值和当前键。如果不返回当前键。

          这适用于多层嵌套对象。

          const listPaths = (obj, init) => Object.entries(obj)
            .flatMap(([k, v]) => {
              const key = init ? `${init}.${k}` : k
              
              return typeof v === 'object' ? listPaths(v, key) : key
            })
           
          const obj = {
            data1: 'test',
            data2: false,
            data3: {
              test1: 'test',
              test2: 'test',
              data3: {
                'sub-test1': 'sub-test',
                'sub-test2': 'sub-test'
              }
            }
          }
          
          const result = listPaths(obj)
          
          console.log(result)

          【讨论】:

            【解决方案6】:

            正如其他答案所提到的,在这种情况下可以使用递归。

            以下是另一个我觉得很容易理解的实现。它使用typeofArray.Mapspread,并且可以处理任何层次深度。

            function getKeys(obj) {
             let keys = [];
             for(const prop in obj){
               if (typeof obj[prop] === "object" && !Array.isArray(obj[prop])) {
                 let subKeys = getKeys(obj[prop]);
                 subKeys = subKeys.map(ele => `${prop}.${ele}`);
                 keys = [...keys, ...subKeys];
               } else {
                 keys = [...keys, prop];
               }
             }
             return keys;
            }
            
            let ob = {
              data1: 'test',
              data2: true,
              data3: {
                test1: 'test',
                test2: 'test',
                data4: {
                  hello: 1
                }
              }
            }
            
            console.log(getKeys(ob));

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2021-10-28
              • 2019-12-26
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-07-19
              • 1970-01-01
              相关资源
              最近更新 更多