Underscore Convert array to object keys - javascript

I am trying to convert this array to an object. Using underscore, I want to convert this array :
[
{
"id": "parentA",
"children": [
{
"name": "name1"
},
{
"name": "name2"
},
{
"name": "name3"
}
]
},
{
"id": "parentB",
"children": [
{
"name": "name4"
},
{
"name": "name5"
},
{
"name": "name6"
}
]
}]
into an object that looks like this:
{
"name1": "parentA",
"name2": "parentA",
"name3": "parentA",
"name4": "parentB",
"name5": "parentB",
"name6": "parentB"
}
I'm really just looking for the cleanest/simplest way possible.

Here's a fairly short way to do it with two reduce:
var data = [
{
"id": "parentA",
"children": [
{
"name": "name1"
},
{
"name": "name2"
},
{
"name": "name3"
}
]
},
{
"id": "parentB",
"children": [
{
"name": "name4"
},
{
"name": "name5"
},
{
"name": "name6"
}
]
}];
var out = _.reduce(data, function(result, parent) {
_.reduce(parent.children, function(r, child) {
r[child.name] = parent.id;
return r;
}, result);
return result;
}, {});
document.write(JSON.stringify(out));
<script src="http://underscorejs.org/underscore-min.js"></script>

var a = [{
"id": "parentA",
"children": [{
"name": "name1"
}, {
"name": "name2"
}, {
"name": "name3"
}]
}, {
"id": "parentB",
"children": [{
"name": "name4"
}, {
"name": "name5"
}, {
"name": "name6"
}]
}];
var new_obj = {};
var len = a.length;
for (j = 0; j < len; j++) {
var c = $.extend({}, a[j]);
var children_length = (c.children).length;
for (i = 0; i < children_length; i++) {
var temp = ((a[j].children)[i]).name;
new_obj[temp] = c.id;
}
}
document.write(JSON.stringify(new_obj));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

You'll only need to use underscore if you're supporting browsers without native reduce and forEach array methods, but you can do it like this.
var result = _.reduce(array, function(memo, entry) {
_.each(entry.children, function(child) {
memo[child.name] = entry.id;
});
return memo;
}, {});

function expand(list){
return _.reduce(list,function(a,b) {
_.each(b.children, function(c) {
a[c.name] = b.id;
});
return a;
},{});
}
Check the output for your sample here

Related

map values to an array inside an object

I have this object below
{
"root": {
"data": {
"page": 1,
"contents": [
{
"node": {
"id": "UzpfSTE",
"stats": {
"viewers": {
"nodes": [
{
"id": "1",
"name": "John"
},
{
"id": "2",
"name": "Shaun"
}
]
}
}
}
},
{
"node": {
"id": "UzpfSTG",
"stats": {
"viewers": {
"nodes": [
{
"id": "3",
"name": "Liam"
}
]
}
}
}
}
]
}
}
}
There is contents node, each of them will have many viewers, all I want is to extract all viewers name to an array, in this instance my result will be [John, Shaun, Liam]
I have this approach:
const data = JSON.parse(rt)
const contents = data.root.data.contents
const newArray = []
for (i = 0; i < contents.length; i++) {
arr2 = contents[i].node.stats.viewers.nodes
for (n = 0; n < arr2.length; n++) {
name = arr2[n].name
newArray.push(name)
}
}
console.log(newArray)
>>> [John, Shaun, Liam]
Which does the job, but occasionaly the object key names change and I have to alter everytime.
So is there more elegant way to do this?
You can simplify that imperative logic like this.
I don't understand what you mean by "the object key names change" though
const data = {
"root": {
"data": {
"page": 1,
"contents": [{
"node": {
"id": "UzpfSTE",
"stats": {
"viewers": {
"nodes": [{
"id": "1",
"name": "John"
},
{
"id": "2",
"name": "Shaun"
}
]
}
}
}
},
{
"node": {
"id": "UzpfSTG",
"stats": {
"viewers": {
"nodes": [{
"id": "3",
"name": "Liam"
}]
}
}
}
}
]
}
}
}
const names = data.root.data.contents.flatMap(({
node: {
stats: {
viewers: {
nodes
}
}
}
}) => nodes.map(({
name
}) => name))
console.log(names)
const data = JSON.parse(rt)
const contents = data.root.data.contents
const viewers = contents.map(item => item.node.stats.viewers.nodes).flat()
const viewerNames = viewers.map(viewer => viewer.name)

Javascript get name from data by id function

I need to create a function the would return the name of the car when given the id.
I have this data:
{
"cars": [
{
"id": "661",
"name": "ford"
},
{
"id": "657",
"name": "fiat",
},
{
"id": "654",
"name": "volvo",
},
{
"id": "653",
"name": "porche",
},
{
"id": "650",
"name": "mazda",
}
]
}
So I've done this:
function getCarNameFromId(id) {
theData = {
"cars": [
{
"id": "661",
"name": "ford"
},
{
"id": "657",
"name": "fiat",
},
{
"id": "654",
"name": "volvo",
},
{
"id": "653",
"name": "porche",
},
{
"id": "650",
"name": "mazda",
}
]
};
console.log(theData.name);
}
then call it:
function getCarNameFromId('650');
How do I finish this code so I can get the code to return me the name of the id specified?
JS solution
var findCar = function(id) {
var theData = {
"cars": [{
"id": "661",
"name": "ford"
},
{
"id": "657",
"name": "fiat",
},
{
"id": "654",
"name": "volvo",
},
{
"id": "653",
"name": "porche",
},
{
"id": "650",
"name": "mazda",
}
]
};
for (var i = 0; i < theData.cars.length; i++) {
var car = theData.cars[i];
if (car.id === id)
return car.name;
}
}
console.log(findCar("654"));
If you are using any mordenr browser you can use find method to find object from array
function getCarNameFromId(id) {
......
..........
.....
var obj = theData.cars.find( function(el) {
return el.id == id
})
if(obj){
return obj.name
} else {
return ''; // or just without any value.
}
}
if still want to support old browsers i would recommand to use lodash.js or underscore.js
cars.find(car => car.id === id).name
Reference:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

Building new JSON from existing one

I want to build an new JSON from existing one. The source has sections and rubrics that I no longer need for a listing. The new object called 'items' should have an array of the items.
The final JSON should be sorted by attribute 'name' and look like
{
"items": [
{
"id": 10000006,
"name": "Boah"
},
{
"id": 10000013,
"name": "Gut"
},
{
"id": 10000003,
"name": "Ipsum"
},
{
"id": 10000001,
"name": "Lorem"
},
{
"id": 10000005,
"name": "Lorum"
},
{
"id": 10000004,
"name": "Name"
},
{
"id": 10000002,
"name": "Stet"
}
]
}
For building the new JSON I get this source:
{
"sections": [
{
"name": "FooBar",
"rubrics": [
{
"name": "Foo",
"items": [
{
"id": 10000001,
"name": "Lorem"
},
{
"id": 10000002,
"name": "Stet"
},
{
"id": 10000003,
"name": "Ipsum"
}
]
},
{
"name": "Bar",
"items": [
{
"id": 10000004,
"name": "Name"
},
{
"id": 10000005,
"name": "Lorum"
},
{
"id": 10000006,
"name": "Boah"
}
]
}
]
},
{
"name": "BlahBloob",
"rubrics": [
{
"name": "Bla",
"items": [
{
"id": 10000013,
"name": "Gut"
}
]
},
{
"name": "Bloob",
"items": [
{
"id": 10000014,
"name": "Name"
},
{
"id": 10000015,
"name": "Lorem"
}
]
}
]
}
]
}
What do you think? How can I do this with plain JavaScript or maybe TypeScript?
Thanks for reading and have time for my question. And thanks for reply in advance.
Here you go. You just need to iterate over each rubric of each section of your source to get the items. At the end, sort your list of items by items, and you're done.
This example uses ES6 syntax, but it's easy to convert it to ES5 if needed.
function extractItems(source) {
const items = [];
for (const section of source.sections) {
for (const rubric of section.rubrics) {
items.push(...rubric.items);
}
}
items.sort((a, b) => a.name.localeCompare(b.name));
return { items };
}
A more functional approach use map and reduce to pick the rubrics and merge them.
data.sections
.map(section => section.rubrics) // get rubrics
.reduce((a, b) => a.concat(b)) // merge rubrics
.map(rubric => rubric.items) // get items from each rubric
.reduce((a, b) => a.concat(b)) // merge items
.sort((a, b) => a.name.localeCompare(b.name)); // sort
function(oldObj) {
var newObj = {
"items": []
};
oldObj.sections.forEach(function(section) {
section.rubrics.forEach(function(rubric) {
rubric.items.forEach(function(item) {
newObj.items.push(item);
});
});
});
newObj.items = newObj.items.sort(function(a, b) {
if (a.name < b.name) { return -1; }
if (a.name > b.name) { return 1; }
return 0;
});
return newObj;
}
And simply use JSON.parse() and JSON.stringify() to convert JSON to and from objects.
It might help you
var data ={
"sections": [
{
"name": "FooBar",
"rubrics": [{"name": "Foo", "items": [{"id": 10000001,"name": "Lorem"}, {"id": 10000002,"name": "Stet"}, {"id": 10000003,"name": "Ipsum"}]
}, {
"name": "Bar",
"items": [{
"id": 10000004,
"name": "Name"
}, {
"id": 10000005,
"name": "Lorum"
}, {
"id": 10000006,
"name": "Boah"
}]
}]
}, {
"name": "BlahBloob",
"rubrics": [{
"name": "Bla",
"items": [{
"id": 10000013,
"name": "Gut"
}]
}, {
"name": "Bloob",
"items": [{
"id": 10000014,
"name": "Name"
}, {
"id": 10000015,
"name": "Lorem"
}]
}]
}]
};
var itemObj = {};
var itemArr = [];
var sections = data.sections;
for(var i=0;i<sections.length;i++)
{
for(var j=0;j<sections[i].rubrics.length;j++){
for(var k=0;k<sections[i].rubrics[j].items.length;k++){
var itemObj;
itemObj['id'] = sections[i].rubrics[j].items[k].id;
itemObj['name'] = sections[i].rubrics[j].items[k].name;
itemArr.push(itemObj);
}
}
}
var finalObj = {"items":itemArr};
console.log(finalObj);
JSFiddle

creating new object with values of another object in javascript

How can we change the structure of the below data object using JavaScript. Needs to categorize all the names under the std. Thanks in advance
[
{
"name": "Rohan",
"std": "3"
},
{
"name": "Jack",
"std": "2"
},
{
"name": "Peter",
"std": "2"
}
]
to
[
{
"std": "2",
"details": [
{
"name": "Jack"
},
{
"name": "Peter"
}
]
},
{
"std": "3",
"details": [
{
"name": "Rohan"
}
]
}
]
The solution using Array.forEach, Array.map and Object.keys functions:
var arr = [{"name": "Rohan", "std": "3"}, { "name": "Jack", "std": "2" }, { "name": "Peter", "std": "2" }],
grouped = {}, result;
arr.forEach(function(obj){
var std = obj['std'];
if (this[std]) {
this[std]['details'].push({'name' : obj['name']});
} else {
this[std] = {'std' : std, 'details' : [{'name' : obj['name']}]};
}
}, grouped);
result = Object.keys(grouped).map((k) => grouped[k]);
console.log(JSON.stringify(result, 0, 4));
The output:
[
{
"std": "2",
"details": [
{
"name": "Jack"
},
{
"name": "Peter"
}
]
},
{
"std": "3",
"details": [
{
"name": "Rohan"
}
]
}
]
You can use reduce() method here
var data = [{
"name": "Rohan",
"std": "3"
}, {
"name": "Jack",
"std": "2"
}, {
"name": "Peter",
"std": "2"
}],
res = [],
kmap = {};
res = data.reduce(function(a, b) {
// check std value already in array using kmap object
if (kmap[b.std]) {
// if already exist then push name attribute in the details
a[kmap[b.std] - 1].details.push({
'name': b.name
});
} else {
// in else case push the new object
a.push({
'std': b.std,
'details': [{
'name': b.name
}]
});
kmap[b.std] = a.length; // storing the (index + 1) value to avoid 0 in if condition
}
return a;
}, []);
console.log(res);
For older browsers check polyfill option for reduce method.
Problems like this are good candidates for recursion. Here is one possible recursive solution. You can make it much prettier using a functional programming framework such as underscore.js.
var objs = [
{
"name": "Rohan",
"std": "3"
},
{
"name": "Jack",
"std": "2"
},
{
"name": "Peter",
"std": "2"
}
];
function categorize(objs) {
if (objs.length === 0) {
return [];
} else {
var first = objs.shift();
var categorized = categorize(objs);
for(var i = 0; i < categorized.length; i++) {
if (categorized[i].std === first.std) {
categorized[i].details.push({name: first.name});
break;
}
}
if(i === categorized.length) {
categorized.push({std: first.std, details: [{name: first.name}]});
}
return categorized;
}
}
var res = categorize(objs);
console.log(res);
If you're using lodash (I know the question didn't ask this and it's going to be slower, but it may be useful to someone :))
var data = [
{ "name": "Rohan", "std": "3" },
{ "name": "Jack", "std": "2" },
{ "name": "Peter", "std": "2" }
];
var grouped = _.chain(data)
.groupBy('std')
.map(function (people, std) {
return {
std: std,
details: _.map(people, function(person) {
return { name: person.name };
})
}
}).value();

Recurse through tree to create a list of breadcrumbs

I have a tree of data and am trying to create a recursive function to add each path in the tree as an array of strings to better understand recursion. I am not sure why my method is not producing the expect
var tree = {
"name": "home",
"children": [
{
"name": "cars",
"children": [
{
"name": "ford",
"children": [
{
"name": "mustang"
},
{
"name": "explorer"
}
]
}
]
},
{
"name": "food",
"children": [
{
"name": "pizza"
}
]
}
]
};
var list = [];
var path = [];
function traverse(node) {
if (node.name) {
path.push(node.name)
}
if (!node.children) {
if (path.length) {
list.push(path);
}
return;
} else {
node.children.forEach(function(item) {
traverse(item);
});
}
}
traverse(tree);
console.log(list);
The output I am looking to create is:
[
["home"],
["home", "cars"],
["home", "cars", "ford"],
["home", "cars", "ford", "mustang"],
["home", "cars", "ford", "explorer"],
["home", "food"],
["home", "food", "pizza"]
]
You modify the same path array in all iterations. You should copy it instead:
var list = [];
function traverse(node, path) {
if ( !path )
path = [];
if (node.name) {
path.push(node.name)
}
list.push(path);
if (node.children) {
node.children.forEach(function(item) {
traverse(item, path.slice());
});
}
}
traverse(tree, []);
I have corrected your code, this solution copies the path variable from one function call to the other:
var tree = {
"name": "home",
"children": [{
"name": "cars",
"children": [{
"name": "ford",
"children": [{
"name": "mustang"
}, {
"name": "explorer"
}]
}]
}, {
"name": "food",
"children": [{
"name": "pizza"
}]
}]
};
var path = [];
var list = [];
function traverse(node, path) {
if ( !path )
path = [];
if (node.name) {
path.push(node.name)
}
list.push(path);
if (node.children) {
node.children.forEach(function(item) {
traverse(item, path.slice());
});
}
document.write(JSON.stringify(path )+ '<br>')
}
traverse(tree, []);

Categories

Resources