1

I have an array of dot delimited strings which looks like the following

data = [
    'Europe.UK.London.TrafalgarSq', 
    'Europe.UK.London.HydePark', 
    'Europe.UK.London.OxfordStreet', 
    'Europe.UK.London.City.Bank', 
    'Europe.France.Paris', 
    'Europe.France.Bordeaux'},
]

and I want to build the following tree of of nested objects. In case it matters, this is for a leaflet map where the Tree Layers Control is going to be used

var tree = {
    label: 'Places',
    selectAllCheckbox: 'Un/select all',
    children: [
        {
            label: 'Europe',
            selectAllCheckbox: true,
            children: [
                {
                    label: 'Europe.UK',
                    selectAllCheckbox: true,
                    children: [
                        {
                            label: 'Europe.UK.London',
                            selectAllCheckbox: true,
                            children: [
                                {label: 'Europe.UK.London.TrafalgarSq'},
                                {label: 'Europe.UK.London.HydePark'},
                                {label: 'Europe.UK.London.OxfordStreet'},
                                {
                                    label: 'Europe.UK.London.City',
                                    selectAllCheckbox: true,
                                    children: [
                                        {label: 'Europe.UK.London.City.Bank'},
                                    ]
                                },
                            ]
                        },
                        {
                            label: 'Europe.France',
                            selectAllCheckbox: true,
                            children: [
                                {label: 'Europe.France.Paris'},
                                {label: 'Europe.France.Bordeaux'},
                            ]
                        },
                    ]

                }
            ]

        }
    ]
};

How do I do this tree please?

1
  • 2
    have you tried anything? Commented Jun 20, 2020 at 18:57

2 Answers 2

4

You could use a mapper object which has partial paths (or label) as key and a reference to the object in the tree as it's value. split the path at . and reduce the array with tree as the initialValue. If the path doesn't exist yet, add it to mapper and tree. Return the nested object in each iteration.

const data = ["Europe.UK.London.TrafalgarSq","Europe.UK.London.HydePark","Europe.UK.London.OxfordStreet","Europe.UK.London.City.Bank","Europe.France.Paris","Europe.France.Bordeaux"],
    mapper = {},
    tree = {
      label: 'Places',
      selectAllCheckbox: 'Un/select all',
      children: []
    }

for (const str of data) {
  let splits = str.split('.'),
      label = '';

  splits.reduce((parent, place) => {
    if (label)
      label += `.${place}`
    else
      label = place

    if (!mapper[label]) {
      const o = { label };
      mapper[label] = o;
      parent.selectAllCheckbox = true
      parent.children = parent.children || [];
      parent.children.push(o)
    }

    return mapper[label];
  }, tree)
}

console.log(tree)

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks so much for this! I spent most of the Saturday trying to do it and I got nothing at all. I am now trying to understand your solution. Can you please explain a bit more mapper, parent and the return value from the reducer? parent at the next iteration should take the return value of the reducer ( which is mapper[label]) but how the tree gets gradually built up please? Also those 3 lines inside the if statement in the reducer where you set the key/value pairs of the parent object can you expand a bit please. How is this related to the tree object please? Thx again!
4

You could an iterative approach with a reduceing of the nested objects.

var data = ['Europe.UK.London.TrafalgarSq', 'Europe.UK.London.HydePark', 'Europe.UK.London.OxfordStreet', 'Europe.UK.London.City.Bank', 'Europe.France.Paris', 'Europe.France.Bordeaux'],
    children = data.reduce((r, s) => {
        s.split('.').reduce((q, _, i, a) => {
            q.selectAllCheckbox = true;
            var label = a.slice(0, i + 1).join('.'),
                temp = (q.children = q.children || []).find(o => o.label === label);
            if (!temp) q.children.push(temp = { label });
            return temp;
        }, r);
        return r;
    }, { children: [] }).children,
    tree = { label: 'Places', selectAllCheckbox: 'Un/select all', children };

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

1 Comment

Thanks Nina for your help! I am really poor with the reduce function but I try to understand it. In its basic form, like multiplication/addition I am ok but I really struggle with more demanding cases. The main reason I accepted adigas answer is because it looks a bit simpler for my understanding.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.