How to combine and select JSON calls? - javascript

How to combine 2 json and appear together? If I choose one that has childern (like click MEN button), then childern in MEN will appear. But if element don't have childern, then the click function is not active.
And if I click the back button, it will bring up the previous menu.
So, the first time, I want to bring up
MEN
WOMEN
KIDS
Customer Care
Contact
And if I click the "MEN" button, will appear
back
accesoris
cloting
shoes
If I click the "back" button, it will return 1 step earlier. Not returning, like the first time.
You can see, This is my imagination to combine 2 json. I don't know how to combine 2 json. Maybe like this
$.each(first, second, function(i, value) {
var first = [{
"id": 1,
"text": "MEN",
"children": [{
"id": 10,
"text": "back"
},
{
"id": 11,
"text": "accesoris",
"children": [{
"id": 110,
"text": "back"
},
{
"id": 111,
"text": "hat",
},
{
"id": 112,
"text": "belt",
}
]
},
{
"id": 12,
"text": "cloting",
"children": [{
"id": 120,
"text": "back"
},
{
"id": 121,
"text": "blazer",
},
{
"id": 122,
"text": "pants",
}
]
},
{
"id": 13,
"text": "shoes",
"children": [{
"id": 130,
"text": "back"
},
{
"id": 131,
"text": "oxford",
},
{
"id": 132,
"text": "chukka",
}
]
}
]
},
{
"id": 2,
"text": "WOMEN",
"children": [{
"id": 20,
"text": "back"
},
{
"id": 21,
"text": "accesoris",
"children": [{
"id": 210,
"text": "back"
},
{
"id": 211,
"text": "ring",
},
{
"id": 212,
"text": "glove",
}
]
},
{
"id": 22,
"text": "cloting",
"children": [{
"id": 220,
"text": "back"
},
{
"id": 221,
"text": "tshirt",
},
{
"id": 222,
"text": "dress",
}
]
},
{
"id": 23,
"text": "shoes",
"children": [{
"id": 230,
"text": "back"
},
{
"id": 231,
"text": "sandals",
},
{
"id": 232,
"text": "heels",
}
]
}
]
},
{
"id": 3,
"text": "KIDS"
}
]
var second = [{
"id": 1,
"text": "Customer Care",
"children": [{
"id": 10,
"text": "back"
},
{
"id": 11,
"text": "Product Information"
},
{
"id": 12,
"text": "Payment Information"
},
{
"id": 13,
"text": "Your Order"
}]
},
{
"id": 2,
"text": "Contact",
"children": [{
"id": 20,
"text": "back"
},
{
"id": 21,
"text": "Careers"
},
{
"id": 22,
"text": "Affiliates"
}]
}
]
// Appears the first time
var text = [];
$.each(first, function(i, value) {
text += '<a>' + value.text + '</a><br>';
$('.result').html(text);
});
// Im not sure its correct, because im using first and second together
// var text = [];
// $.each(first, second, function(i, value) {
// text[i] += '<a>' + value.text + '</a><br>';
// $('.result').html(text[i]);
// });
// Function if a button is pressed
$(document).click('a', function(e) {
if ($(this).text() == 'back') {
// Go back one step, not back to the beginning
} else {
// function text() ----> $('.result').html(text);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="result"></div>

If you want to combine two arrays together you can just use concat.
var fullList = first.concat(second);

ok so this a jQuery version
var
first = [
{ "id": 1, "text": "MEN", "children": [
{ "id": 10, "text": "back" },
{ "id": 11, "text": "accesoris", "children": [
{ "id": 110, "text": "back" },
{ "id": 111, "text": "hat" },
{ "id": 112, "text": "belt" }
]},
{ "id": 12, "text": "cloting", "children": [
{ "id": 120, "text": "back" },
{ "id": 121, "text": "blazer" },
{ "id": 122, "text": "pants" }
]},
{ "id": 13, "text": "shoes", "children": [
{ "id": 130, "text": "back" },
{ "id": 131, "text": "oxford" },
{ "id": 132, "text": "chukka" }
]}
]},
{ "id": 2, "text": "WOMEN", "children": [
{ "id": 20, "text": "back" },
{ "id": 21, "text": "accesoris", "children": [
{ "id": 210, "text": "back" },
{ "id": 211, "text": "ring" },
{ "id": 212, "text": "glove" }
]},
{ "id": 22, "text": "cloting", "children": [
{ "id": 220, "text": "back" },
{ "id": 221, "text": "tshirt" },
{ "id": 222, "text": "dress" }
]},
{ "id": 23, "text": "shoes", "children": [
{ "id": 230, "text": "back" },
{ "id": 231, "text": "sandals" },
{ "id": 232, "text": "heels" }
]}
]},
{ "id": 3, "text": "KIDS" }
]
,
second = [
{ "id": 1, "text": "Customer Care", "children": [
{ "id": 10, "text": "back" },
{ "id": 11, "text": "Product Information" },
{ "id": 12, "text": "Payment Information" },
{ "id": 13, "text": "Your Order" }
]},
{ "id": 2, "text": "Contact", "children": [
{ "id": 20, "text": "back" },
{ "id": 21, "text": "Careers" },
{ "id": 22, "text": "Affiliates" }
]}
];
;
const
fullList = first.concat(second) ,
$myList = $('#my-List') ;
var
List_Level = [] ,
current_List = fullList ;
function ShowList_F()
{
let xList = fullList;
for (let x=0, xMax=List_Level.length; x<xMax; x++)
{
xList = xList[ List_Level[x] ].children;
}
$myList.empty()
current_List = xList;
for (let i=0, iMax=xList.length; i<iMax; i++)
{
let aClass = 'levelentry' + (xList[i].hasOwnProperty('children')?' PLUS':''); // other possibility
$myList.append( `<li class="root-level"><a class="${aClass}" data-ref="${i}">${xList[i].text}</a></li>`);
}
}
ShowList_F(); // first attempt
$myList.on( "click", "a", function(e)
{
e.preventDefault();
let xItem = parseInt( $(this).data('ref') );
if ($(this).text()==='back') // level Up
{
List_Level.pop()
ShowList_F();
}
else if (current_List[xItem].hasOwnProperty('children')) // level Down (and same test)
{
List_Level.push(xItem);
ShowList_F();
}
})
#my-List { cursor: pointer; list-style-type:none }
.PLUS::before { content: '- '}
.PLUS:hover::before { content: '+'}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id="my-List"></ul>

so it's a complete solution, unfortunately I lost the habit of coding jQuery, so it's an ES6 solution (which I find really less complicated)
var
first = [
{ "id": 1, "text": "MEN", "children": [
{ "id": 10, "text": "back" },
{ "id": 11, "text": "accesoris", "children": [
{ "id": 110, "text": "back" },
{ "id": 111, "text": "hat" },
{ "id": 112, "text": "belt" }
]},
{ "id": 12, "text": "cloting", "children": [
{ "id": 120, "text": "back" },
{ "id": 121, "text": "blazer" },
{ "id": 122, "text": "pants" }
]},
{ "id": 13, "text": "shoes", "children": [
{ "id": 130, "text": "back" },
{ "id": 131, "text": "oxford" },
{ "id": 132, "text": "chukka" }
]}
]},
{ "id": 2, "text": "WOMEN", "children": [
{ "id": 20, "text": "back" },
{ "id": 21, "text": "accesoris", "children": [
{ "id": 210, "text": "back" },
{ "id": 211, "text": "ring" },
{ "id": 212, "text": "glove" }
]},
{ "id": 22, "text": "cloting", "children": [
{ "id": 220, "text": "back" },
{ "id": 221, "text": "tshirt" },
{ "id": 222, "text": "dress" }
]},
{ "id": 23, "text": "shoes", "children": [
{ "id": 230, "text": "back" },
{ "id": 231, "text": "sandals" },
{ "id": 232, "text": "heels" }
]}
]},
{ "id": 3, "text": "KIDS" }
]
,
second = [
{ "id": 1, "text": "Customer Care", "children": [
{ "id": 10, "text": "back" },
{ "id": 11, "text": "Product Information" },
{ "id": 12, "text": "Payment Information" },
{ "id": 13, "text": "Your Order" }
]},
{ "id": 2, "text": "Contact", "children": [
{ "id": 20, "text": "back" },
{ "id": 21, "text": "Careers" },
{ "id": 22, "text": "Affiliates" }
]}
];
;
const
fullList = first.concat(second)
,
myList = document.querySelector('#my-List')
,
Messager = {
_zone : document.getElementById('MsgZone'),
Text(msg) {
this._zone.textContent = msg;
setTimeout(that=>that._zone.textContent='', 900, this);
}
};
var
List_Level = [],
current_List = fullList,
LI_elm = document.createElement('li');
function ShowList_F()
{
let
xList = fullList,
showingTxt = '';
List_Level.forEach( x=>{
showingTxt += ` / ${xList[x].text}`
xList=xList[x].children
})
while( myList.firstChild )
{ myList.removeChild( myList.firstChild ); }
current_List = xList;
xList.forEach((e,i)=>{
let xLI = myList.appendChild(LI_elm.cloneNode(false));
xLI.dataset.ref = i.toString();
xLI.textContent = e.text;
if (e.text==='back') { xLI.className='back' }
})
Messager.Text(showingTxt)
}
ShowList_F(); // first attempt
myList.onclick = function(e)
{
if (!e.target.matches('li')) return;
e.stopPropagation();
let xItem = parseInt(e.target.dataset.ref);
if (e.target.textContent==='back')
{
List_Level.pop()
ShowList_F();
}
else if ( 'children' in current_List[ xItem ])
{
List_Level.push(xItem);
ShowList_F();
}
else
{
Messager.Text('nothing to do with this click')
}
}
#my-List { cursor: pointer; list-style-type:square }
#MsgZone, .back { font-size: 0.8em; font-style: italic }
<ul id="my-List"></ul>
<div id="MsgZone"></div>

Related

d3 hierarchy ability to average children node values

I have a d3 visualization that has a JSON object similar to the following where I would like to average up the value of score on the lowest nodes and dynamically add that average to the parent node above...and so on. It doesn't look like d3 has an easy method to do this. What I'd like is to have the final JSON output look like the second example.
{
"name": "A1",
"children": [
{
"name": "B1",
"children": [
{
"name": "B1-C1",
"children": [
{
"name": "B1-C1-D1",
"children": [
{
"name": "B1-C1-D1-E1",
"value": 30,
"score": 0.8
},
{
"name": "B1-C1-D1-E2",
"value": 35,
"score": 0.5
}
]
},
{
"name": "B1-C1-D2",
"children": [
{
"name": "B1-C1-D2-E1",
"value": 31,
"score": 0.4
},
{
"name": "B1-C1-D2-E2",
"value": 23,
"score": 0.7
}
]
}
]
}
]
}
]
}
What I'd like the final JSON object to look like:
{
"name": "A1",
"scoreAvg": 0.625,
"children": [
{
"name": "B1",
"scoreAvg": 0.625,
"children": [
{
"name": "B1-C1",
"scoreAvg": 0.625,
"children": [
{
"name": "B1-C1-D1",
"scoreAvg": 0.7,
"children": [
{
"name": "B1-C1-D1-E1",
"value": 30,
"score": 0.8
},
{
"name": "B1-C1-D1-E2",
"value": 35,
"score": 0.6
}
]
},
{
"name": "B1-C1-D2",
"scoreAvg": 0.55,
"children": [
{
"name": "B1-C1-D2-E1",
"value": 31,
"score": 0.4
},
{
"name": "B1-C1-D2-E2",
"value": 23,
"score": 0.7
}
]
}
]
}
]
}
]
}
You can use a recursive function:
const obj = {
"name": "A1",
"children": [{
"name": "B1",
"children": [{
"name": "B1-C1",
"children": [{
"name": "B1-C1-D1",
"children": [{
"name": "B1-C1-D1-E1",
"value": 30,
"score": 0.8
},
{
"name": "B1-C1-D1-E2",
"value": 35,
"score": 0.5
}
]
},
{
"name": "B1-C1-D2",
"children": [{
"name": "B1-C1-D2-E1",
"value": 31,
"score": 0.4
},
{
"name": "B1-C1-D2-E2",
"value": 23,
"score": 0.7
}
]
}
]
}]
}]
}
function getWithAverageScore(objToRecurse) {
// If I have a score I am already done
if (objToRecurse.score) {
return objToRecurse;
}
// Otherwise, I get my children with their average score
const children = objToRecurse.children.map(getWithAverageScore);
return {
...objToRecurse,
children,
// And I set my scoreAvg to their average (score or scoreAvg)
scoreAvg: children.reduce((total, { score, scoreAvg }) => total + (score || scoreAvg), 0) / children.length
};
}
console.log(JSON.stringify(getWithAverageScore(obj), null, 2))
let o = {
"name": "A1",
"children": [
{
"name": "B1",
"children": [
{
"name": "B1-C1",
"children": [
{
"name": "B1-C1-D1",
"children": [
{
"name": "B1-C1-D1-E1",
"value": 30,
"score": 0.8
},
{
"name": "B1-C1-D1-E2",
"value": 35,
"score": 0.5
}
]
},
{
"name": "B1-C1-D2",
"children": [
{
"name": "B1-C1-D2-E1",
"value": 31,
"score": 0.4
},
{
"name": "B1-C1-D2-E2",
"value": 23,
"score": 0.7
}
]
}
]
}
]
}
]
};
function avgUp(object){
object.avgScore = 0;
if(object.children){
for(child of object.children){
object.avgScore += avgUp(child);
}
object.avgScore = object.avgScore /Math.max(1,object.children.length);
return object.avgScore;
}else{
return object.score;
}
}
avgUp(o);
console.log(JSON.stringify(o));

Using angularjs forEach loops

I am getting this type of json in my $scope of angularjs:
$scope.someStuff = {
"id": 2,
"service": "bike",
"min": "22",
"per": "100",
"tax": "1",
"categoryservices": [
{
"id": 32,
"category": {
"id": 1,
"name": "software"
}
},
{
"id": 33,
"category": {
"id": 2,
"name": "hardware"
}
},
{
"id": 34,
"category": {
"id": 3,
"name": "waterwash"
}
}
]
}
I want to use angularjs forEach loop and i want to get only category name,
My expected output:
[{"name":"software"}, {"name":"hardware"}, {"name":"waterwash"}]
You can use Array.map()
The map() method creates a new array with the results of calling a provided function on every element in the calling array.
$scope.someStuff.categoryservices.map((x) => { return { name: x.category.name}})
var obj = {
"id": 2,
"service": "bike",
"min": "22",
"per": "100",
"tax": "1",
"categoryservices": [{
"id": 32,
"category": {
"id": 1,
"name": "software"
}
},
{
"id": 33,
"category": {
"id": 2,
"name": "hardware"
}
},
{
"id": 34,
"category": {
"id": 3,
"name": "waterwash"
}
}
]
};
console.log(obj.categoryservices.map((x) => {
return {
name: x.category.name
}
}))
You can use map method by passing a callback function as parameter.
const someStuff = { "id": 2, "service": "bike", "min": "22", "per": "100", "tax": "1", "categoryservices": [ { "id": 32, "category": { "id": 1, "name": "software" } }, { "id": 33, "category": { "id": 2, "name": "hardware" } }, { "id": 34, "category": { "id": 3, "name": "waterwash" } } ] }
let array = someStuff.categoryservices.map(function({category}){
return {'name' : category.name}
});
console.log(array);

How to find all unique paths in tree structure

root1
child1
child2
grandchild1
grandchild2
child3
root2
child1
child2
grandchild1
greatgrandchild1
I have an object array like tree structure like above, I want to get all unique paths in like this
Food->Dry Food Items->Local Dry Food Items
Food->Dry Food Items->Thai Dry Food Items
Food->Dry Food Items->Others
Food->Fruits
------
------
This is my object
[
{
"id": 1,
"name": "Food",
"parent_id": 0,
"children": [
{
"id": 5,
"name": "Dry Food Items",
"parent_id": 1,
"children": [
{
"id": 11,
"name": "Local Dry Food Items",
"parent_id": 5
},
{
"id": 12,
"name": "Thai Dry Food Items",
"parent_id": 5
},
{
"id": 60,
"name": "Others",
"parent_id": 5
}
]
},
{
"id": 6,
"name": "Fruits",
"parent_id": 1
},
{
"id": 7,
"name": "LG Branded",
"parent_id": 1
},
{
"id": 8,
"name": "Meat",
"parent_id": 1
},
{
"id": 9,
"name": "Sea food",
"parent_id": 1
},
{
"id": 10,
"name": "Vegetables",
"parent_id": 1,
"children": [
{
"id": 14,
"name": "Local Vegetables",
"parent_id": 10
},
{
"id": 15,
"name": "Thai Vegetables",
"parent_id": 10
}
]
},
{
"id": 38,
"name": "Frozen",
"parent_id": 1
},
{
"id": 39,
"name": "IP Kitchen",
"parent_id": 1,
"children": [
{
"id": 40,
"name": "IP Meat",
"parent_id": 39
},
{
"id": 41,
"name": "IP Starter",
"parent_id": 39
},
{
"id": 42,
"name": "IP Ingredients",
"parent_id": 39
},
{
"id": 43,
"name": "IP Sauce",
"parent_id": 39
},
{
"id": 44,
"name": "IP Seafood",
"parent_id": 39
},
{
"id": 45,
"name": "IP Starter",
"parent_id": 39
},
{
"id": 46,
"name": "IP Desert",
"parent_id": 39
}
]
}
]
},
{
"id": 2,
"name": "Beverage",
"parent_id": 0,
"children": [
{
"id": 16,
"name": "Bar",
"parent_id": 2
},
{
"id": 17,
"name": "Coffee & Tea",
"parent_id": 2
},
{
"id": 18,
"name": "In Can",
"parent_id": 2
},
{
"id": 19,
"name": "Water",
"parent_id": 2
},
{
"id": 47,
"name": "IP Bar",
"parent_id": 2
}
]
},
{
"id": 3,
"name": "Disposable",
"parent_id": 0,
"children": [
{
"id": 21,
"name": "Disposable",
"parent_id": 3
}
]
},
{
"id": 4,
"name": "SOE",
"parent_id": 0,
"children": [
{
"id": 20,
"name": "Cleaning Materials",
"parent_id": 4
},
{
"id": 22,
"name": "Chinaware",
"parent_id": 4
}
]
}
];
I get to all the nodes in the tree
function traverse(categories) {
categories.forEach(function (category) {
if (category.children && category.children.length) {
traverse(category.children);
}
else {
}
}, this);
}
You can use recursion and create a function using forEach loop.
var arr = [{"id":1,"name":"Food","parent_id":0,"children":[{"id":5,"name":"Dry Food Items","parent_id":1,"children":[{"id":11,"name":"Local Dry Food Items","parent_id":5},{"id":12,"name":"Thai Dry Food Items","parent_id":5},{"id":60,"name":"Others","parent_id":5}]},{"id":6,"name":"Fruits","parent_id":1},{"id":7,"name":"LG Branded","parent_id":1},{"id":8,"name":"Meat","parent_id":1},{"id":9,"name":"Sea food","parent_id":1},{"id":10,"name":"Vegetables","parent_id":1,"children":[{"id":14,"name":"Local Vegetables","parent_id":10},{"id":15,"name":"Thai Vegetables","parent_id":10}]},{"id":38,"name":"Frozen","parent_id":1},{"id":39,"name":"IP Kitchen","parent_id":1,"children":[{"id":40,"name":"IP Meat","parent_id":39},{"id":41,"name":"IP Starter","parent_id":39},{"id":42,"name":"IP Ingredients","parent_id":39},{"id":43,"name":"IP Sauce","parent_id":39},{"id":44,"name":"IP Seafood","parent_id":39},{"id":45,"name":"IP Starter","parent_id":39},{"id":46,"name":"IP Desert","parent_id":39}]}]},{"id":2,"name":"Beverage","parent_id":0,"children":[{"id":16,"name":"Bar","parent_id":2},{"id":17,"name":"Coffee & Tea","parent_id":2},{"id":18,"name":"In Can","parent_id":2},{"id":19,"name":"Water","parent_id":2},{"id":47,"name":"IP Bar","parent_id":2}]},{"id":3,"name":"Disposable","parent_id":0,"children":[{"id":21,"name":"Disposable","parent_id":3}]},{"id":4,"name":"SOE","parent_id":0,"children":[{"id":20,"name":"Cleaning Materials","parent_id":4},{"id":22,"name":"Chinaware","parent_id":4}]}]
function getNames(data) {
var result = [];
function loop(data, c) {
data.forEach(function (e) {
var name = !c.length ? e.name : c + '->' + e.name;
if (e.children) { loop(e.children, name); }
else {
result.push({ name: name });
}
});
}
loop(data, '');
return result;
}
console.log(getNames(arr))

How to collect value in javascript?

I have an array like this in Javascript. Something like this
[
{
"id": 1,
"facilities": [
{
"id": 10,
"name": "Wifi",
"label": "Wifi"
},
{
"id": 12,
"name": "Toll",
"label": "Toll"
}
]
},
{
"id": 2,
"facilities": [
{
"id": 10,
"name": "Wifi",
"label": "Wifi"
},
{
"id": 12,
"name": "Toll",
"label": "Toll"
},
{
"id": 13,
"name": "Snack",
"label": "Snack"
}
]
},
{
"id": 3,
"facilities": [
{
"id": 10,
"name": "Wifi",
"label": "Wifi"
},
{
"id": 12,
"name": "Toll",
"label": "Toll"
},
{
"id": 14,
"name": "Petrol",
"label": "Petrol"
}
]
}
]
I want to collect data and grouping data facilities of the array in Javascript, something like this.
"facilities": [
{
"id": 10,
"name": "Wifi",
"label": "Wifi"
},
{
"id": 12,
"name": "Toll",
"label": "Toll"
},
{
"id": 13,
"name": "Snack",
"label": "Snack"
},
{
"id": 14,
"name": "Petrol",
"label": "Petrol"
}
]
So, basically, group by facilities. I just don't know how to handle the grouping of similar facilities values.
Assuming the facility ids are unique:
const facilities = input.reduce((memo, entry) => {
entry.facilities.forEach((f) => {
if (!memo.some((m) => m.id === f.id)) {
memo.push(f)
}
})
return memo
}, [])
You can iterate through all rows and collect (id, entity) map.
Index map allows us to not search already collected entities every time.
Then you can convert it to an array with object keys mapping.
let input = [
{"id": 1, "facilities": [{"id": 10, "name": "Wifi", "label": "Wifi"}, {"id": 12, "name": "Toll", "label": "Toll"} ] },
{"id": 2, "facilities": [{"id": 10, "name": "Wifi", "label": "Wifi"}, {"id": 12, "name": "Toll", "label": "Toll"}, {"id": 13, "name": "Snack", "label": "Snack"} ] },
{"id": 3, "facilities": [{"id": 10, "name": "Wifi", "label": "Wifi"}, {"id": 12, "name": "Toll", "label": "Toll"}, {"id": 14, "name": "Petrol", "label": "Petrol"} ] }
];
let index = input.reduce((res, row) => {
row.facilities.forEach(f => res[f.id] = f);
return res;
}, {});
let result = Object.keys(index).map(id => index[id]);
console.log({facilities: result});
You could use a Set for flagging inserted objects with the given id.
var data = [{ id: 1, facilities: [{ id: 10, name: "Wifi", label: "Wifi" }, { id: 12, name: "Toll", label: "Toll" }] }, { id: 2, facilities: [{ id: 10, name: "Wifi", label: "Wifi" }, { id: 12, name: "Toll", label: "Toll" }, { id: 13, name: "Snack", label: "Snack" }] }, { id: 3, facilities: [{ id: 10, name: "Wifi", label: "Wifi" }, { id: 12, name: "Toll", label: "Toll" }, { id: 14, name: "Petrol", label: "Petrol" }] }],
grouped = data.reduce(
(s => (r, a) => (a.facilities.forEach(b => !s.has(b.id) && s.add(b.id) && r.push(b)), r))(new Set),
[]
);
console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }
The solution using Array.prototype.reduce() and Set object:
var data = [{"id": 1,"facilities": [{"id": 10,"name": "Wifi","label": "Wifi"},{"id": 12,"name": "Toll","label": "Toll"}]},{"id": 2,"facilities": [{"id": 10,"name": "Wifi","label": "Wifi"},{"id": 12,"name": "Toll","label": "Toll"},{"id": 13,"name": "Snack","label": "Snack"}]},{"id": 3,"facilities": [{"id": 10,"name": "Wifi","label": "Wifi"},{"id": 12,"name": "Toll","label": "Toll"},{"id": 14,"name": "Petrol","label": "Petrol"}]}
];
var ids = new Set(),
result = data.reduce(function (r, o) {
o.facilities.forEach(function(v) { // iterating through nested `facilities`
if (!ids.has(v.id)) r.facilities.push(v);
ids.add(v.id); // saving only items with unique `id`
});
return r;
}, {facilities: []});
console.log(result);
const input = [
{
"id": 1,
"facilities": [
{
"id": 10,
"name": "Wifi",
"label": "Wifi"
},
{
"id": 12,
"name": "Toll",
"label": "Toll"
}
]
},
{
"id": 2,
"facilities": [
{
"id": 10,
"name": "Wifi",
"label": "Wifi"
},
{
"id": 12,
"name": "Toll",
"label": "Toll"
},
{
"id": 13,
"name": "Snack",
"label": "Snack"
}
]
},
{
"id": 3,
"facilities": [
{
"id": 10,
"name": "Wifi",
"label": "Wifi"
},
{
"id": 12,
"name": "Toll",
"label": "Toll"
},
{
"id": 14,
"name": "Petrol",
"label": "Petrol"
}
]
}
]
const result = []
const idx = []
for (const item of input) {
for (const facilityItem of item.facilities) {
if (!idx.includes(facilityItem.id)) {
idx.push(facilityItem.id)
result.push(facilityItem)
}
}
}
console.log(result)
A very simple and easily understood approach.
const data = [{
"id": 1,
"facilities": [{
"id": 10,
"name": "Wifi",
"label": "Wifi"
},
{
"id": 12,
"name": "Toll",
"label": "Toll"
}
]
},
{
"id": 2,
"facilities": [{
"id": 10,
"name": "Wifi",
"label": "Wifi"
},
{
"id": 12,
"name": "Toll",
"label": "Toll"
},
{
"id": 13,
"name": "Snack",
"label": "Snack"
}
]
},
{
"id": 2,
"facilities": [{
"id": 10,
"name": "Wifi",
"label": "Wifi"
},
{
"id": 12,
"name": "Toll",
"label": "Toll"
},
{
"id": 14,
"name": "Petrol",
"label": "Petrol"
}
]
}
];
let o = {};
let result = [];
data.forEach((d) => {
d.facilities.forEach((f) => {
o[f.id] = f;
});
});
for (let r in o) {
result.push(o[r]);
}
console.log(result);

How to get the ids of nested array once the condition is met?

I've a nested array, once the condition is met, it should give all the parent ids e.g. I've a data array, in which I should match the
getParentIds(data, 182, []);
result: [96, 182];
getParentIds(data, 174, []);
result: [109 , 219, 76 ,174];
var data = [{
"id": 96,
"name": "test1",
"items": [{
"id": 181,
"name": "Yes",
"items": []
}, {
"id": 182,
"name": "No",
"items": []
}]
}, {
"id": 109,
"name": "Test5",
"items": [{
"id": 219,
"name": "opt2",
"items": [{
"id": 76,
"name": "test3",
"items": [{
"id": 173,
"name": "Yes",
"items": []
}, {
"id": 174,
"name": "No",
"items": [{
"id": 100,
"name": "test2",
"items": [{
"id": 189,
"name": "Yes",
"items": []
}]
}]
}]
}]
}, {
"id": 224,
"name": "opt3",
"items": []
}]
}];
function getParentIds(data, id, parentIds) {
if (!parentIds) {
parentIds = [];
}
data.map(function(item) {
if (item.id === id) {
parentIds.push(item.id);
return parentIds;
} else if (item.items.length === 0) {
// do nothing
} else {
return getParentIds(item.items, id, parentIds);
}
});
}
console.log("Array list: " + getParentIds(data, 182, []));
Could you give me any suggestion on this?
This was a cool problem. It took me more than I expected to solve it, but here's a breadth-first search implementation:
var data = [{
"id": 96,
"name": "test1",
"items": [{
"id": 181,
"name": "Yes",
"items": []
}, {
"id": 182,
"name": "No",
"items": []
}]
}, {
"id": 109,
"name": "Test5",
"items": [{
"id": 219,
"name": "opt2",
"items": [{
"id": 76,
"name": "test3",
"items": [{
"id": 173,
"name": "Yes",
"items": []
}, {
"id": 174,
"name": "No",
"items": [{
"id": 100,
"name": "test2",
"items": [{
"id": 189,
"name": "Yes",
"items": []
}]
}]
}]
}]
}, {
"id": 224,
"name": "opt3",
"items": []
}]
}];
function parentsOf( arr, id, parents){
if (parents.length)
return parents;
// I use for(;;) instead of map() because I need the return to exit the loop
for (var i = 0; i < arr.length; i++){
if ( arr[i].id == id){
//push the current element at the front of the parents array
parents.unshift( arr[i].id );
return parents;
};
if ( arr[i].items ){
parents = parentsOf(arr[i].items, id, parents);
// if the parents array has any elements in it it means we found the child
if (parents.length){
parents.unshift(arr[i].id);
return parents;
}
}
}
return parents;
}
console.log("Array list for 182: " + parentsOf(data, 182, []));
console.log("Array list for 174: " + parentsOf(data, 174, []));
If this task will be done repeatedly it would be a clever approach first to flatten the nested array into a hash table where the keys would be id properties. While flattening you can add a parents property to the objects. Then the search would be as simple and fast as accessing an object property on the hash table. The following demonstrates the mentioned approach.
var data = [{
"id": 96,
"name": "test1",
"items": [{
"id": 181,
"name": "Yes",
"items": []
}, {
"id": 182,
"name": "No",
"items": []
}]
}, {
"id": 109,
"name": "Test5",
"items": [{
"id": 219,
"name": "opt2",
"items": [{
"id": 76,
"name": "test3",
"items": [{
"id": 173,
"name": "Yes",
"items": []
}, {
"id": 174,
"name": "No",
"items": [{
"id": 100,
"name": "test2",
"items": [{
"id": 189,
"name": "Yes",
"items": []
}]
}]
}]
}]
}, {
"id": 224,
"name": "opt3",
"items": []
}]
}],
getParents = (ar, id) => {var fData = (a, pid, pin) => a.reduce((p,c) => {c.parents = pid.concat();
p[c.id] = c;
c.items.length && fData(c.items, pid.concat(c.id), p);
return p;
}, pin);
return fData(ar,[],{})[id].parents;
}; //so much for getParents
document.write("<pre>" + JSON.stringify(getParents(data, 189), null, 2) + "</pre>");

Categories

Resources