fe-learning icon indicating copy to clipboard operation
fe-learning copied to clipboard

树形数据结构扁平化

Open metroluffy opened this issue 5 years ago • 2 comments

编写两个函数,实现如下两个数据结构互相转换

const data = {
  a: {
    b: {
      c: {
        dd: 'abcdd'
      }
    },
    d: {
      xx: 'adxx'
    },
    e: 'ae'
  }
}
const output = {
  'a.b.c.dd': 'abcdd',
  'a.d.xx': 'adxx',
  'a.e': 'ae'
}

metroluffy avatar May 21 '20 08:05 metroluffy

// 辅助函数
const isObj = obj => Object.prototype.toString.call(obj) === '[object Object]'

// 扁平化树形结构
function flattenNTreeHelper (data, ans, prevKey = '') {
  Object.keys(data).forEach(key => {
    const currKey = prevKey ? prevKey + '.' + key : key
    const currVal = data[key]
    if (isObj(currVal)) {
      flattenNTreeHelper(currVal, ans, currKey)
    } else {
      ans[currKey] = currVal
    }
  })
}
function flattenNTree (data) {
  if (!isObj(data)) return data
  const ans = {}
  flattenNTreeHelper(data, ans, '')
  return ans
}
// 扁平化结构转树形
function nTreeConstruct (data) {
  if (!isObj(data)) return data
  const ans = {}
  Object.keys(data).forEach(key => {
    // 按 . 分割key, 顺带支持一下形如 'z[0]'的格式
    const keys = key.replace(/\[(\d+)\]/g, '.$1').split('.')
    let curr = ans
    for (let i = 0; i < keys.length - 1; i++) {
      curr[keys[i]] = curr[keys[i]] || {}
      curr = curr[keys[i]]
    }
    curr[keys[keys.length - 1]] = data[key]
  })
  return ans
}

metroluffy avatar May 21 '20 08:05 metroluffy

再考虑以下数据:

const data = {
  a: {
    b: {
      c: {
        dd: 'abcdd'
      }
    },
    e: 'ae',
    g: [1, { g1: 6 }, [1, 2]]
  }
}
// 期望输出
const output = {
   'a.b.c.dd': 'abcdd',
   'a.e': 'ae',
   'g[0]': 1,
   'g[1].g1': 6,
   'g[2][0]': 1,
   'g[2][1]': 2
}

也就是生成key的时候要多考虑一个数组类型,实现如下:

function flattenNTreeHelper (data, ans, prevKey = '', isArr = false) {
  Object.keys(data).forEach(key => {
    const currKey = prevKey ? (prevKey + (isArr ? ('[' + key + ']') : ('.' + key))) : key
    const currVal = data[key]
    const dataIsArr = Array.isArray(currVal)
    if (isObj(currVal) || dataIsArr) {
      flattenNTreeHelper(currVal, ans, currKey, dataIsArr)
    } else {
      ans[currKey] = currVal
    }
  })
}

metroluffy avatar May 22 '20 03:05 metroluffy