John Dawn
John Dawn

Reputation: 95

array of strings to tree data structure

There is data returned from server containing an array of strings as hierarchy like this:

[
 "house.bedroom.bed",
 "house.kitchen.spoon",
 "house.kitchen.knife",
 "house.bedroom.sofa",
 "house.bedroom.tv",
 "plants.trees",
 "house.birds.parrot.grey"
 ...]

how do i create a tree data structure out of it to make Output the data in tree form.

like this:

root
  house
    bedroom
      bed
      sofa
      tv
    kitchen
      spoon
      knife
    birds
      parrot
        grey
  plants
    trees

what is the most simple way to do so ?

and is there any way to reverse it ? for example of asked knife i want to return house.kitchen.knife

thanks in advance

Upvotes: 6

Views: 3312

Answers (4)

Nina Scholz
Nina Scholz

Reputation: 386868

You could take an array with nested arrays where the first element is the name.

For finding a wanted string, it uses a recursive approach by keeping the path to the actual elements for later joining a wanted string.

... right, why an array and not a funky object? Glad that you asked. Arrays allows to maintain a specific order without relying on actual implementation of ordered objects.

function find([key, values], string, temp = []) {
    var result;
    temp = temp.concat(key);
    if (key === string) {
        return temp.slice(1).join('.');
    }
    values.some(a => result = find(a, string, temp));
    return result;
}

var array = ["house.bedroom.bed", "house.kitchen.spoon", "house.kitchen.knife", "house.bedroom.sofa", "house.bedroom.tv", "plants.trees", "house.birds.parrot.grey"],
    result = array.reduce((r, s) => {
        ('root.' + s).split('.').reduce((a, item) => {
            var array = a.find(([v]) => v === item);
            if (!array) {
                a.push(array = [item, []]);
            }
            return array[1];
        }, r);
        return r;
    }, []).pop();

console.log(find(result, 'knife')); // house.kitchen.knife
console.log(find(result, '42'));    // undefined, what else?
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 5

Shl
Shl

Reputation: 3688

const data = [
    "house.bedroom.bed",
    "house.kitchen.spoon",
    "house.kitchen.knife",
    "house.bedroom.sofa",
    "house.bedroom.tv",
    "plants.trees",
    "house.birds.parrot.grey"
];

const mainMapFromStart = {};
const mainMapFromEnd = {};
function set(parts, mainMap) {
    let map = mainMap;
    for(const item of parts) {
        map[item] = map[item] || {};
        map = map[item];
    }
}

data.map(item => item.split('.')).forEach(parts => {
    set(parts, mainMapFromStart);
    set(parts.reverse(), mainMapFromEnd);
});

console.log(JSON.stringify(mainMapFromStart, null, 4));
console.log(JSON.stringify(mainMapFromEnd, null, 4));

This code will return this structure in mainMap in both ways:

output:
{
    "house": {
        "bedroom": {
            "bed": {},
            "sofa": {},
            "tv": {}
        },
        "kitchen": {
            "spoon": {},
            "knife": {}
        },
        "birds": {
            "parrot": {
                "grey": {}
            }
        }
    },
    "plants": {
        "trees": {}
    }
}
{
    "bed": {
        "bedroom": {
            "house": {}
        }
    },
    "spoon": {
        "kitchen": {
            "house": {}
        }
    },
    "knife": {
        "kitchen": {
            "house": {}
        }
    },
    "sofa": {
        "bedroom": {
            "house": {}
        }
    },
    "tv": {
        "bedroom": {
            "house": {}
        }
    },
    "trees": {
        "plants": {}
    },
    "grey": {
        "parrot": {
            "birds": {
                "house": {}
            }
        }
    }
}

Upvotes: 4

Afron Orana
Afron Orana

Reputation: 635

Code below will give you the last string that includes the keyword. Let me know if this wasn't what you were looking for.

let stringsArray = [
  "house.bedroom.bed",
  "house.kitchen.spoon",
  "house.kitchen.knife",
  "house.bedroom.sofa",
  "house.bedroom.tv",
  "plants.trees",
  "house.birds.parrot.grey"
];

function findInArray() {
let keyword = document.getElementById('search').value;
  let results = document.getElementById('results');
  stringsArray.forEach(function(string, index) {
    if (string.includes(keyword)) {
      results.innerHTML = string;
    }
  });
}
<label for="search">Search for:</label>
<input type="text" id="search">
<button type="button" onclick='findInArray()'>Search</button>

<span id="results"></span>

Upvotes: -2

dandavis
dandavis

Reputation: 16726

here's one way to do it, might not be the most efficient, but works. If you don't want the leafs as empty objects, you can modify it as needed.

var r=[
 "house.bedroom.bed",
 "house.kitchen.spoon",
 "house.kitchen.knife",
 "house.bedroom.sofa",
 "house.bedroom.tv",
 "plants.trees",
 "house.birds.parrot.grey"];

var o={}; // output object
function build(o,p){
 p.split(".").forEach(function(d){
   o = o[d] || (o[d]={});  
 });
}    

r.forEach(function(a,i){ // build up each branch based on path
 build(o, a);
});
o

Upvotes: 3

Related Questions