Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

217
Visualizações
Transform dot notation to a tree data form

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

about 4 years ago · Juan Pablo Isaza
2 Respostas
Responde à pergunta

0

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)

about 4 years ago · Juan Pablo Isaza Relatório

0

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.

about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda