I need to convert this array of strings into a special structure
https://github.com/jonmiles/bootstrap-treeview
This is my Input String array:
******************
"productone"
"productone\level2\level3"
"productwo"
"productwo\level2\level3\level4"
"productwo\level2\level3.1\level4\level5"
"productwo\level2\level3.2\level4\level5"
so can you imagine this:
"memory"
"memory\ram"
"memory\ram\ddr\sodimm\533mhz\4gb"
"memory\ram\ddr\sodimm\533mhz\8gb"
"memory\ram\ddr\sodimm\533mhz\16gb"
"memory\ram\ddr\sodimm2\633mh\4gb
"memory\ram\ddr\sodimm2\633mh\16gb
"memory\disk"
and so on....
*******************
And I need this Output (pay attention at return correct order output):
var jsondata = [
{
"text": "productone",
"nodes":[ {"text": "level2",
"nodes":[{"text": "level3"}]
}]
},
{
"text": "productwo",
"nodes":[{"text": "level2"},
"nodes":[{"text": "level3",
"nodes":[{text:level4}]
}]
}]
}
}]
Any suggestion?
I threw away my previous answer to replace it with this one.
This should do exactly what you want.
var src = [
"productone",
"productone\\level2\\level3",
"productwo\\level2\\level3\\level4",
"productone\\level2\\dog",
"productone\\level2\\dog\\bark",
"productwo\\level2\\level3a\\level4a",
"productwo\\level2\\level3\\level4\\level5",
"productwo\\food\\desserts\\cookies",
"productwo\\food\\desserts\\cakes",
"productwo\\food\\desserts\\pies",
"productone\\level2\\cat",
"productone\\level2\\cat\\meow"
]
function tempToObj(temp) {
var result = [];
Object.keys(temp).forEach(
function(key) {
var obj = {
text: key
};
var nodes = tempToObj(temp[key]);
if (nodes.length > 0) {
obj.nodes = nodes;
}
result.push(obj);
}
);
return result;
}
function strsToObj(strList) {
var result = [];
var tempResult = {};
function buildNode(parts, idx, obj) {
var key = parts[idx];
obj[key] = obj[key] || {};
idx++;
if (idx < parts.length) {
buildNode(parts, idx, obj[key]);
}
}
strList.forEach(
function(str) {
var parts = str.split('\\');
buildNode(parts, 0, tempResult);
}
);
return tempToObj(tempResult);
}
var obj = strsToObj(src);
console.log(JSON.stringify(obj,0,2));
I found it much easier to just build of an object structure and then convert it into the format you wanted. That simplified the parsing algorithm and yet prevents rebuilding everything each time.
The result of the code above is this:
[
{
"text": "productone",
"nodes": [
{
"text": "level2",
"nodes": [
{
"text": "level3"
},
{
"text": "dog",
"nodes": [
{
"text": "bark"
}
]
},
{
"text": "cat",
"nodes": [
{
"text": "meow"
}
]
}
]
}
]
},
{
"text": "productwo",
"nodes": [
{
"text": "level2",
"nodes": [
{
"text": "level3",
"nodes": [
{
"text": "level4",
"nodes": [
{
"text": "level5"
}
]
}
]
},
{
"text": "level3a",
"nodes": [
{
"text": "level4a"
}
]
}
]
},
{
"text": "food",
"nodes": [
{
"text": "desserts",
"nodes": [
{
"text": "cookies"
},
{
"text": "cakes"
},
{
"text": "pies"
}
]
}
]
}
]
}
]
I have solve my problem and I have transform to Javacript pure code this
Brandon Clapp article
You can string#split each string inside array#map and use array#reduceRight to check for nodes and text value inside your result object. If text key is present at a level, reassign your object to nodes key and populate text key with the current text value.
var strings = ["productone","productone\\level2\\level3","productwo\\level2\\level3\\level4"];
const result = strings.map(string => string.split('\\').reduceRight((r,text, index) => {
if(r['text'])
r['nodes'] = [Object.assign({}, r)];
r['text'] = text;
return r;
},{}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could take a hash table with a nested approach by taking the given part strings as identifiert for nested objects for collecting all data.
Later this proposal deletes unwanted nodes without content.
This approach works for unsorted data.
var array = ["productone", "productone\\level2\\level3", "productwo\\level2\\level3\\level4"],
result = [],
hash = { _: result };
array.forEach(function (a) {
a.split('\\').reduce(function (r, k) {
if (!r[k]) {
r[k] = { _: [] };
r._.push({ text: k, nodes: r[k]._ });
}
return r[k];
}, hash);
});
result.forEach(function clean(o) {
if (o.nodes.length) {
o.nodes.forEach(clean);
} else {
delete o.nodes;
}
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Related
I have a data array
var data=[{
"key": "KUZEY",
"items": [
{
"key": "MARMARA",
"items": [
{
"key": "T100",
"items": [
{
"Ref": 1,
"ApprovedReserveQuantity": 1
}
]
}
]
},
{
"key": "MARMARA 2",
"items": [
{
"key": "T100",
"items": [
{
"Ref": 2,
"ApprovedReserveQuantity": 1
}
]
}
]
}
] }]
İ want to get items when i call function. how can do that recursiveMethod?
groupedItems=recursiveMethod(data)
groupedItems==>[{"Ref": 1,"ApprovedReserveQuantity": 1},{"Ref": 2,"ApprovedReserveQuantity": 1}]
groupedItems:any[]=[];
recursiveMethod(element){
if(element.items==null)
this.groupedItems.push(element)
if (element.items != null){
let i;
for(i=0; i < element.items.length; i++){
this.recursiveMethod(element.items[i]);
}
}
}
it's worked
Couldn't find any 'key' checking in your answer.
Even though I don't trust my function completely, and am confused for as why it worked, It can be reusable if you tweak/adjust it.
const extractInnermostByKey = (data, targetKey, res = []) => {
data.forEach((obj) => {
for (let key of Object.keys(obj)) {
if (key === targetKey) {
// console.log(res); observe res
res.shift();
res.push(...obj[key]);
return extractInnermostByKey(res, targetKey, res);
}
}
});
return res;
};
const groupedItems = extractInnermostByKey(data, 'items');
console.log(groupedItems);
I have a Json data that I want to have in a different format.
My original json data is:
{
"info": {
"file1": {
"book1": {
"lines": {
"102:0": [
"102:0"
],
"105:4": [
"106:4"
],
"106:4": [
"107:1",
"108:1"
]
}
}
}
}
}
And I want to map it as following:
{
"name": "main",
"children": [
{
"name": "file1",
"children": [
{
"name": "book1",
"group": "1",
"lines": [
"102",
"102"
],
[
"105",
"106"
],
[
"106",
"107",
"108"
]
}
],
"group": 1,
}
],
"group": 0
}
But the number of books and number of files will be more. Here in the lines the 1st part (before the :) inside the "" is taken ("106:4" becomes "106"). The number from the key goes 1st and then the number(s) from the value goes and make a list (["106", "107", "108"]). The group information is new and it depends on parent-child information. 1st parent is group 0 and so on. The first name ("main") is also user defined.
I tried the following code so far:
function build(data) {
return Object.entries(data).reduce((r, [key, value], idx) => {
//const obj = {}
const obj = {
name: 'main',
children: [],
group: 0,
lines: []
}
if (key !== 'reduced control flow') {
obj.name = key;
obj.children = build(value)
if(!(key.includes(":")))
obj.group = idx + 1;
} else {
if (!obj.lines) obj.lines = [];
Object.entries(value).forEach(([k, v]) => {
obj.lines.push([k, ...v].map(e => e.split(':').shift()))
})
}
r.push(obj)
return r;
}, [])
}
const result = build(data);
console.log(result);
The group information is not generating correctly. I am trying to figure out that how to get the correct group information. I would really appreciate if you can help me to figure it out.
You could use reduce method and create recursive function to build the nested structure.
const data = {"info":{"file1":{"book1":{"lines":{"102:0":["102:0"],"105:4":["106:4"],"106:4":["107:1","108:1"]}}}}}
function build(data) {
return Object.entries(data).reduce((r, [key, value]) => {
const obj = {}
if (key !== 'lines') {
obj.name = key;
obj.children = build(value)
} else {
if (!obj.lines) obj.lines = [];
Object.entries(value).forEach(([k, v]) => {
obj.lines.push([k, ...v].map(e => e.split(':').shift()))
})
}
r.push(obj)
return r;
}, [])
}
const result = build(data);
console.log(result);
I couldn't understand the logic behind group property, so you might need to add more info for that, but for the rest, you can try these 2 functions that recursively transform the object into what you are trying to get.
var a = {"info":{"file1":{"book1":{"lines":{"102:0":["102:0"],"105:4":["106:4"],"106:4":["107:1","108:1"]}}}}};
var transform = function (o) {
return Object.keys(o)
.map((k) => {
return {"name": k, "children": (k === "lines" ? parseLines(o[k]) : transform(o[k])) }
}
)
}
var parseLines = function (lines) {
return Object.keys(lines)
.map(v => [v.split(':')[0], ...(lines[v].map(l => l.split(":")[0]))])
}
console.log(JSON.stringify(transform(a)[0], null, 2));
I'm having some difficulties with recursive functions. Can someone help me?
I have the following structure:
{
"entity": {
"entityLabel": "Virtual Reality",
"parent": [
{
"entity": {
"entityLabel": "Artificial Intelligence",
"parent": [
{
"entity": {
"entityLabel": "Information Technology"
}
}
]
}
}
]
}
}
And I need the following result:
{
"label": "Information Technology",
"children": [
{
"label": "Artificial Intelligence"
"children": [
{
label: "Virtual Reality"
}
]
}
]
}
I couldn't accomplish the reverse order. My current code is:
const termTree = term => {
const label = term.entity?.entityLabel
const parentArr = term.entity?.parent
const obj = {}
let children = []
if (parentArr) {
children = parentArr.map(item => {
return termTree(item)
})
}
obj.label = label
if (!empty(children)) obj.children = children
return obj
}
Which results in the same order but with different labels:
{
"label": "Virtual Reality",
"children": [
{
"label": "Artificial Intelligence",
"children": [
{
"label": "Information Technology"
}
]
}
]
}
As you can see it's reverse and it's not just a matter of changing labels.
Thanks
You could take an iterative and recursive approach by handing over a source array for the new label and a target array for the final result with children.
By taking the above wanted format, without a children property in the most inner object, this approach take as target an object with a children. The reducing part for generating the new data structure takes only objects as return value and creates children if necessary.
var data = { entity: { entityLabel: "Virtual Reality", parent: [{ entity: { entityLabel: "Artificial Intelligence", parent: [{ entity: { entityLabel: "Information Technology" } }] } }] } },
result = [];
[data].forEach(function iter(source, target) {
return function ({ entity: { entityLabel, parent } }) {
source = [entityLabel, ...source];
if (parent) return parent.forEach(iter(source, target));
source.reduce((t, label) => {
var temp = (t.children = t.children || []).find(o => o.label === label);
if (!temp) {
t.children.push(temp = { label });
}
return temp;
}, target);
}
}([], { children: result }));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Array 1 = Accessories:Bracket,Accessories:Clamp,Actuator:Accessories,Actuator:Accessories:Bracket,Actuator:Accessories:Clamp,Actuator:Clevis
Array 2 = 24092859,24092784,24094450,24094451,24110219,24092811
Required Output =
[
{
"text": "Accessories",
"children": [
{
"text": "Bracket",
"children": [],
"mtdtId": "24092859"
},
{
"text": "Clamp",
"children": [],
"mtdtId": "24092784"
}
],
"mtdtId": "24092859,24092784"
},
{
"text": "Actuator",
"children": [
{
"text": "Accessories",
"children": [
{
"text": "Bracket",
"children": [],
"mtdtId": "24094451"
},
{
"text": "Clamp",
"children": [],
"mtdtId": "24110219"
}
],
"mtdtId": "24110219,24094451"
},
{
"text": "Clevis",
"children": [],
"mtdtId": ""
}
],
"mtdtId": "24110219,24094451"
}
]
the parent should contain the id's of the child nodes.
const array1 = "Accessories:Bracket,Accessories:Clamp,Actuator:Accessories,Actuator:Accessories:Bracket,Actuator:Accessories:Clamp,Actuator:Clevis".split(
","
);
const array2 = "24092859,24092784,24094450,24094451,24110219,24092811".split(
","
);
const output = array1.reduce(
(topLevelNodes, path, i) => {
let nodes = topLevelNodes;
let mtdId = array2[i];
path.split(":").forEach(text => {
let node = nodes.filter(child => child.text === text)[0];
if (node) {
node.mtdId += "," + mtdId;
} else {
nodes.push((node = { text, children: [], mtdId }));
}
nodes = node.children;
});
return topLevelNodes;
},
[]
);
console.log(output);
You could use a hash table for the nested elements and get later all values of mtdtId for grouping of the children elements. I suggest to use a different property for the collection.
var array1 = 'Engines:Combustion,Engines:Combustion:AeroThermal,Engines:Combustion:Fuel Systems,Engines:Combustion:Mechanical,Engines:Fans & Compressors,Engines:Fans & Compressors:Centrifugal Compressor Aero'.split(','),
array2 = '001,002,003,004,005,006'.split(','),
result = [];
array1.forEach(function (a, i) {
a.split(':').reduce(function (r, k, j, kk) {
if (!r[k]) {
r[k] = { _: [] };
r._.push(j + 1 === kk.length ? { text: k, mtdtId: array2[i], children: r[k]._ } : { text: k, children: r[k]._ });
}
return r[k];
}, this);
}, { _: result });
result.reduce(function iter(r, a) {
var temp = a.mtdtId ? [a.mtdtId] : [];
if (Array.isArray(a.children)) {
temp = a.children.reduce(iter, temp);
}
if (a.mtdtId !== temp.join()) {
a.collected = temp.join();
}
return r.concat(temp);
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I have an object like this:
{
"id": 23,
"name": "Jacob",
"link": {
"rel": "self",
"link": "www.abc.com"
},
"company":{
"data":{
"id": 1,
"ref": 324
}
}
I want to store each key with its value to an array in javascript or typescript like this
[["id":23], ["name":"Jacob"], ["link":{......, ......}]] and so on
I am doing this so that I can append an ID for each.
My best guess I would loop through the array and append an ID/a flag for each element, which I don't know how to do as well.... how to address this issue ? thanks
var arr = [];
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
var innerObj = {};
innerObj[prop] = obj[prop];
arr.push(innerObj)
}
}
console.log(arr);
here is demo https://plnkr.co/edit/9PxisCVrhxlurHJYyeIB?p=preview
p.forEach( function (country) {
country.forEach( function (entry) {
entry.push( {"value" : 'Greece', "synonyms" : 'GR'});
});
});
you can try to use experimental Object.entries:
let obj = {
"id": 23,
"name": "Jacob",
"link": {
"rel": "self",
"link": "www.abc.com"
},
"company":{
"data":{
"id": 1,
"ref": 324
}
}};
console.log(Object.entries(obj).map(item => ({[item[0]]:item[1]})));
for unsupported browsers you can use polyfill: https://github.com/es-shims/Object.entries
You could use an iterative/recursive approach with the object and their nested parts. It works for any depths.
function getKeyValue(object) {
return Object.keys(object).reduce(function (result, key) {
return result.concat(
object[key] && typeof object[key] === 'object' ?
getKeyValue(object[key]) :
[[key, object[key]]]
);
}, []);
}
var data = { id: 23, name: "Jacob", link: { rel: "self", link: "www.abc.com" }, company: { data: { id: 1, ref: 324 } } };
console.log(getKeyValue(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use the Object.keys method to get an array of the keys, then use the Array#map method to return a new array containing individual objects for each property.
This ES6 one-liner should do it:
const splitObject = o => Object.keys(o).map(e => ({ [e]: o[e] }));
Or in ES5:
function splitObject(o) {
return Object.keys(o).map(function(e) {
return Object.defineProperty({}, e, {
value: o[e],
enumerable: true
});
});
}
var res = [];
_.transform( {
"id": 23,
"name": "Jacob",
"link": {
"rel": "self",
"link": "www.abc.com"
},
"company": {
"data": {
"id": 1,
"ref": 324
}
}
}, function(result, value, key) {
res.push(key +':'+value);
}, {});
You can use underscore
Supported in all major browser, including IE11
Object.entries() gives you exactly this.
const obj = {
id: 23,
name: 'Jacob',
link: {
rel: 'self',
link: 'www.abc.com'
},
company: {
data: {
id: 1,
ref: 324
}
}
};
Object.entries(obj);
// output:
[
[
"id",
23
],
[
"name",
"Jacob"
],
[
"link",
{
"rel": "self",
"link": "www.abc.com"
}
],
[
"company",
{
"data": {
"id": 1,
"ref": 324
}
}
]
]
var obj=[{"Name":ABC,"Count":123},{"Name":XYZ,"Count":456}];
var arr = [];
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
var innerObj = {};
innerObj[0] = obj[prop];
arr.push(innerObj[0]);
}
}
/* Here above exmple innerobj index set to 0 then we will get same data into arr if u not menstion then arr will conatins arr[0] our result.
then we need to call first record obj arr[0][0] like this*/
const foo = { "bar": "foobar", "foo": "foobar" }
Object.entries(foo)
should result in:
[["bar", "foobar"], ["foo", "foobar"]]
maybe there's a function to pass to convert all commas to colons
Here's the documentation
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries