将点符号转换为树数据表

发布于 2025-01-22 17:28:40 字数 2101 浏览 0 评论 0原文

我的形式有面向对象的数据:

var alist = [
    'foo',
    'foo.lol1',
    'foo.lol2',
    'bar.lol1',
    'bar.barbar.kk',
    ...
]

我想转换为树结构,能够用树组件将它们提供服务( https://github.com/vinz3872/vuejs-tree )。要求表格如下:

var ok = [
    {
        text: "foo",
        state: { expanded: false },
        nodes: [
            {
                id: 1,
                path: "foo.lol1",
                text: "lol1",
                checkable: true,
                state: { checked: false },
            },
            {
                id: 2,
                path: "foo.lol2",
                text: "lol2",
                checkable: true,
                state: { checked: false },
            },
        ]
    },
    {
        text: "bar",
        state: { expanded: false },
        nodes: [
            {
                id: 3,
                path: "bar.lol1",
                text: "lol1",
                checkable: true,
                state: { checked: false },
            },
        ]
    },
    {
        text: "bar",
        state: { expanded: false },
        nodes: [
            {
                id: 3,
                path: "bar.lol1",
                text: "lol1",
                checkable: true,
                state: { checked: false },
            },
            {
                text: "barbar",
                state: { expanded: false },
                nodes: [
                    {
                        id: 4,
                        path: "bar.barbar.kk",
                        text: "kk",
                        checkable: true,
                        state: { checked: false },
                    },
                ]
            },
        ]
    }
]

我知道我应该使用递归,并且我尝试了所有相关帖子,即如何使用对象点表示法构建JSON树结构。 我的主要问题是,我必须以某种方式保留树叶叶子的完整路径信息。作为JS的新手,我在柜台上失去了几天的柜台和回调,没有任何运气。 感谢您的帮助。 先感谢您

I have object oriented data in the form:

var alist = [
    'foo',
    'foo.lol1',
    'foo.lol2',
    'bar.lol1',
    'bar.barbar.kk',
    ...
]

which I would like to transform into a tree structure, to be able to serve them with a tree component (https://github.com/vinz3872/vuejs-tree in particular). The require form is the following:

var ok = [
    {
        text: "foo",
        state: { expanded: false },
        nodes: [
            {
                id: 1,
                path: "foo.lol1",
                text: "lol1",
                checkable: true,
                state: { checked: false },
            },
            {
                id: 2,
                path: "foo.lol2",
                text: "lol2",
                checkable: true,
                state: { checked: false },
            },
        ]
    },
    {
        text: "bar",
        state: { expanded: false },
        nodes: [
            {
                id: 3,
                path: "bar.lol1",
                text: "lol1",
                checkable: true,
                state: { checked: false },
            },
        ]
    },
    {
        text: "bar",
        state: { expanded: false },
        nodes: [
            {
                id: 3,
                path: "bar.lol1",
                text: "lol1",
                checkable: true,
                state: { checked: false },
            },
            {
                text: "barbar",
                state: { expanded: false },
                nodes: [
                    {
                        id: 4,
                        path: "bar.barbar.kk",
                        text: "kk",
                        checkable: true,
                        state: { checked: false },
                    },
                ]
            },
        ]
    }
]

I am aware that I should use recursion and I have tried all relevan posts in stackoverflow, i.e. How to build a JSON tree structure using object dot notation.
My main problem is that I have to somehow preserve the information of the full path to the leaves of the tree. As a newbie in js I lost myself in counters and callback for days without any luck.
I would appreciate your help.
Thank you in advance

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

疑心病 2025-01-29 17:28:40

基本上,您可以使用foreach,然后将每个字符串拆分为数组,然后在其中使用reald。然后,您构建嵌套对象,其中键是当前路径,也可以是AD到结果数组。

var alist = [
  'foo',
  'foo.lol1',
  'foo.lol2',
  'bar.lol1',
  'bar.barbar.kk',
]

const result = []
const levels = {
  result
}

let prev = ''
let id = 1

alist.forEach(str => {
  str.split('.').reduce((r, text, i, arr) => {
    const path = prev += (prev.length ? '.' : '') + text

    if (!r[path]) {
      r[path] = {result: []}
      
      const obj = {
        id: id++,
        text,
      }
      
      if (i === 0) {
        obj.state = {expanded: false}
      } else {
        obj.state = {checked: false}
        obj.checkable = true
        obj.path = path
      }
      
      obj.nodes = r[path].result
      r.result.push(obj)
    }

    if (i === arr.length - 1) {
      prev = ''
    }

    return r[path]
  }, levels)
})


console.log(result)

Basically you could use forEach then split each string into array and then use reduce on that. Then you build nested object where the keys are current paths and also ad to result array.

var alist = [
  'foo',
  'foo.lol1',
  'foo.lol2',
  'bar.lol1',
  'bar.barbar.kk',
]

const result = []
const levels = {
  result
}

let prev = ''
let id = 1

alist.forEach(str => {
  str.split('.').reduce((r, text, i, arr) => {
    const path = prev += (prev.length ? '.' : '') + text

    if (!r[path]) {
      r[path] = {result: []}
      
      const obj = {
        id: id++,
        text,
      }
      
      if (i === 0) {
        obj.state = {expanded: false}
      } else {
        obj.state = {checked: false}
        obj.checkable = true
        obj.path = path
      }
      
      obj.nodes = r[path].result
      r.result.push(obj)
    }

    if (i === arr.length - 1) {
      prev = ''
    }

    return r[path]
  }, levels)
})


console.log(result)

゛时过境迁 2025-01-29 17:28:40

我发现以两个步骤进行此转换是最简单的。第一个将您的输入转换为此格式:

{
  foo: {
    lol1: {}, 
    lol2: {}
  },
  bar: {
    barbar: {
      kk: {}
    }, 
    lol1: {}
  }, 
}

第二种仅使用此格式来创建所需的结构。这有两个优势。首先,我的工具躺在周围,可以轻松地从您的输入中创建此结构。其次,该结构嵌入了足够的信息来创建您的输出,只有一个分支结构:路径上的值是空对象还是具有属性。这使得代码相对简单:

const setPath = ([p, ...ps]) => (v) => (o) =>
  p == undefined ? v : Object .assign (
    Array .isArray (o) || Number .isInteger (p) ? [] : {},
    {...o, [p]: setPath (ps) (v) ((o || {}) [p])}
  )

const reformat = (o, path = [], nextId = ((id) => () => String (++ id)) (0)) =>
  Object .entries (o) .map (([k, v]) => Object .entries (v) .length > 0
    ? {text: k, state: {exapanded: false}, nodes: reformat (v, [...path, k], nextId)}
    : {id: nextId (), path: [...path, k] .join('.'), text: k, checkable: false, state: {checked: false}}
  )

const transform = (pathTokens) =>
  reformat (pathTokens
    .map (s => s .split ('.'))
    .reduce ((a, path) => setPath (path) ({}) (a), {})
  )


const alist = ['foo', 'foo.lol1', 'foo.lol2', 'bar.lol1', 'bar.barbar.kk']

console .log (transform (alist))
.as-console-wrapper {max-height: 100% !important; top: 0}

我们从setPath开始,该格式以['bar','barbar','kk']的格式开始,该格式在该路径上设置的值,以及沿该路径的新特性的浅克隆的对象。因此,setPath(['foo','bar','baz'])(42)({foo:{qux:7},corge:6}),corge:6})产量{foo {foo:{{ qux:7,bar:{baz:42}},corge:6}。 (此可重复使用的功能中还有更多的内容可以处理数组索引,而不是字符串对象路径,但是我们无法从此输入格式中达到这一点。)

然后,我们具有Regralat,它可以进行格式转换。 。它只是基于输入值是否为空对象来构建不同的输入对象。

最后,变换在输入阵列上映射一个分组功能,以获取setPath 的路径结构,通过将每个路径值设置为空的,将结果折叠到最初的空对象中对象,产生我们的中间格式,然后我们将其调整为重构

我在这里真的不喜欢一件事,那是nextID函数,这是一个状态函数。我们可以很容易地使用生成器功能,但是无论我们在这里做什么,我们都使用状态来构建此输出并困扰我。如果有人对此有更干净的建议,我很想听听。

I found that it was easiest to do this transformation in two steps. The first converts your input into this format:

{
  foo: {
    lol1: {}, 
    lol2: {}
  },
  bar: {
    barbar: {
      kk: {}
    }, 
    lol1: {}
  }, 
}

The second uses just this format to create your desired structure. This has two advantages. First, I have tools lying around that make it easy to create this structure from your input. Second, this structure embeds enough information to create your output, with only one branching construct: whether the value at a path is an empty object or has properties. This makes the generation code relatively simple:

const setPath = ([p, ...ps]) => (v) => (o) =>
  p == undefined ? v : Object .assign (
    Array .isArray (o) || Number .isInteger (p) ? [] : {},
    {...o, [p]: setPath (ps) (v) ((o || {}) [p])}
  )

const reformat = (o, path = [], nextId = ((id) => () => String (++ id)) (0)) =>
  Object .entries (o) .map (([k, v]) => Object .entries (v) .length > 0
    ? {text: k, state: {exapanded: false}, nodes: reformat (v, [...path, k], nextId)}
    : {id: nextId (), path: [...path, k] .join('.'), text: k, checkable: false, state: {checked: false}}
  )

const transform = (pathTokens) =>
  reformat (pathTokens
    .map (s => s .split ('.'))
    .reduce ((a, path) => setPath (path) ({}) (a), {})
  )


const alist = ['foo', 'foo.lol1', 'foo.lol2', 'bar.lol1', 'bar.barbar.kk']

console .log (transform (alist))
.as-console-wrapper {max-height: 100% !important; top: 0}

We start with setPath, which takes a path, in a format such as ['bar', 'barbar', 'kk'], the value to set at that path, and an object to shallow clone with this new property along that path. Thus setPath (['foo', 'bar', 'baz']) (42) ({foo: {qux: 7}, corge: 6}) yields {foo: {qux: 7, bar: {baz: 42}}, corge: 6}. (There's a little more in this reusable function to also handle array indices instead of string object paths, but we can't reach that from this input format.)

Then we have reformat, which does the format conversion. It simply builds a different input object based upon whether the input value is an empty object.

Finally, transform maps a splitting function over your input array to get the path structure needed for setPath, folds the results into an initially empty object by setting every path value to an empty object, yielding our intermediate format, which we then pas to reformat.

There is one thing I really don't like here, and that is the nextId function, which is a stateful function. We could just have easily used a generator function, but whatever we do here, we're using state to build this output and that bothers me. If someone has a cleaner suggestion for this, I'd love to hear it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文