Search array of nested objects with dynamic parameters - javascript

I have an array with objects. I'm trying to recursively search through them and create new array with modified key's.
The array:
let response = {
users: [
{
user_id: 1661871600,
details: {
height: 150,
age: 33,
work: 1015,
school: 10,
degree: 933
},
work: [
{
id: 500,
main: 'Doctor',
description: 'Ofto',
icon: '10d',
},
],
look: {
all: 100,
},
transport: {
speed: 0.62,
max_speed: 349,
},
visibility: 10000,
hair: {
type: 0.26,
},
date: '2022-08-30 15:00:00',
},
{
user_id: 324235256,
details: {
height: 110,
age: 25,
work: 101,
school: 110,
degree: 553
},
work: [
{
id: 500,
main: 'Software',
description: 'Programmer',
icon: '11d',
},
],
look: {
all: 2,
},
transport: {
speed: 1.2,
max_speed: 49,
},
visibility: 221,
hair: {
type: 5.6,
},
date: '2021-01-30 12:00:00',
},
{
user_id: 12353743,
details: {
height: 10,
age: 75,
work: 1,
school: 114,
degree: 3
},
work: [
{
id: 500,
main: 'Pension',
description: 'Architect',
icon: '1d',
},
],
look: {
all: 6,
},
transport: {
speed: 3.2,
max_speed: 29,
},
visibility: 21,
hair: {
type: 1.6,
},
date: '2020-01-30 12:00:00',
},
],
};
I've tried using JSON.Stringify but I keep getting not desired result.
function dynamic(obj, ...keyToFind) {
const foundObj = {};
const foundObjArray: any[] = [];
keyToFind.forEach((key) => {
JSON.stringify(obj, (_, nestedValue) => {
if (nestedValue && nestedValue[a]) {
foundObj[key] = nestedValue[a];
}
return nestedValue;
});
foundObjArray.push(foundObj);
});
return foundObjArray;
}
I'm calling this function with N number of parameters:
dynamic(response, 'age', 'work', 'main', 'description', 'type', 'date');
Once it is called I'm trying to construct a new array of objects who will look like:
let foundObjArray = [
{
'age': 33,
'work': 1015,
'main': 'Doctor',
'description': 'Ofto',
'type': 5.6,
'date': '2022-08-30 15:00:00'
},
{
'age': 25,
'work': 101,
'main': 'Software',
'description': 'Programmer',
'type': 0.26,
'date': '2021-01-30 12:00:00'
},
.......
]

A JSON.stringify based approach, as initially intended by the OP, is even a reliable one, in case one wants to target any user-item's first occurring entry regardless of its nesting level/depth where each property's value is not of object or array type itself.
One just needs to come up with an according property specific regex like e.g. for the "work" key ... /"work":(?<value>[^\[{]+?)(?=,"|\})/.
The rest then can be achieved by combined map and reduce tasks, where with each item's mapping a new object is created via reducing an array of property names which has to be provided as the map method's 2nd thisArg parameter.
const response = {
users: [{
user_id: 1661871600,
details: {
height: 150,
age: 33,
work: 1015,
school: 10,
degree: 933
},
work: [{
id: 500,
main: 'Doctor',
description: 'Ofto',
icon: '10d',
}],
look: {
all: 100,
},
transport: {
speed: 0.62,
max_speed: 349,
},
visibility: 10000,
hair: {
type: 0.26,
},
date: '2022-08-30 15:00:00',
}, {
user_id: 324235256,
details: {
height: 110,
age: 25,
work: 101,
school: 110,
degree: 553
},
work: [{
id: 500,
main: 'Software',
description: 'Programmer',
icon: '11d',
}],
look: {
all: 2,
},
transport: {
speed: 1.2,
max_speed: 49,
},
visibility: 221,
hair: {
type: 5.6,
},
date: '2021-01-30 12:00:00',
}, {
user_id: 12353743,
details: {
height: 10,
age: 75,
work: 1,
school: 114,
degree: 3
},
work: [{
id: 500,
main: 'Pension',
description: 'Architect',
icon: '1d',
}],
look: {
all: 6,
},
transport: {
speed: 3.2,
max_speed: 29,
},
visibility: 21,
hair: {
type: 1.6,
},
date: '2020-01-30 12:00:00',
}],
};
function createObjectOfFirstOccurringValuesFromBoundKeyList(item) {
const itemData = JSON.stringify(item);
return this // `this` equals the bound array of property names.
.reduce((result, key) => {
const { value = null } =
RegExp(`"${ key }":(?<value>[^\[{]+?)(?=,"|\})`)
// see ... [https://regex101.com/r/ss6jlt/1]
.exec(itemData)
?.groups ?? {};
if (value !== null) {
Object
.assign(result, { [key]: JSON.parse(value) });
}
return result;
}, {})
}
const listOfFirstPropertyValueItems = response
.users
.map(createObjectOfFirstOccurringValuesFromBoundKeyList, [
'age', 'work', 'main', 'description', 'type', 'date'
]);
console.log({
listOfFirstPropertyValueItems
});
.as-console-wrapper { min-height: 100%!important; top: 0; }

let response = {
users: [
{
user_id: 1661871600,
details: {
height: 150,
age: 33,
speed_min: 296.76,
speed_max: 297.87,
work: 1015,
school: 10,
degree: 933
},
work: [
{
id: 500,
main: 'Doctor',
description: 'Ofto',
icon: '10d',
},
],
look: {
all: 100,
},
transport: {
speed: 0.62,
max_speed: 349,
},
visibility: 10000,
hair: {
type: 0.26,
},
date: '2022-08-30 15:00:00',
},
{
user_id: 324235256,
details: {
height: 110,
age: 25,
speed_min: 96.76,
speed_max: 327.87,
work: 101,
school: 110,
degree: 553
},
work: [
{
id: 500,
main: 'Software',
description: 'Programmer',
icon: '11d',
},
],
look: {
all: 2,
},
transport: {
speed: 1.2,
max_speed: 49,
},
visibility: 221,
hair: {
type: 5.6,
},
date: '2021-01-30 12:00:00',
},
{
user_id: 12353743,
details: {
height: 10,
age: 75,
speed_min: 16.76,
speed_max: 27.87,
work: 1,
school: 114,
degree: 3
},
work: [
{
id: 500,
main: 'Pension',
description: 'Architect',
icon: '1d',
},
],
look: {
all: 6,
},
transport: {
speed: 3.2,
max_speed: 29,
},
visibility: 21,
hair: {
type: 1.6,
},
date: '2020-01-30 12:00:00',
},
],
};
function getMatchedKey(arr, key) {
let matched = arr.filter(x => key.endsWith(x));
if(matched.length > 0) {
return matched[0];
}
}
function getLimitedData(data, requiredKey = []) {
var result = {};
function recurse(cur, prop) {
if (Object(cur) !== cur) {
let matchedKey = getMatchedKey(requiredKey, prop);
matchedKey != undefined && (result[matchedKey] = cur);
} else if (Array.isArray(cur)) {
for (var i = 0, l = cur.length; i < l; i++)
recurse(cur[i], prop + "[" + i + "]");
if (l == 0) {
let matchedKey = getMatchedKey(requiredKey, prop);
matchedKey != undefined && (result[matchedKey] = []);
}
} else {
var isEmpty = true;
for (var p in cur) {
isEmpty = false;
recurse(cur[p], prop ? prop + "." + p : p);
}
if (isEmpty && prop) {
let matchedKey = getMatchedKey(requiredKey, prop);
matchedKey != undefined && (result[matchedKey] = {});
}
}
}
recurse(data, "");
return result;
}
let keys = ['age', 'work', 'main', 'description', 'type', 'date'];
let output = response.users.map(a => getLimitedData(a, keys));
console.log(output);

you can do like this two by saperating objectFunction and ArrayFunction recursively
let keys = ['age', 'work', 'main', 'description', 'type', 'date'];
let response = {
users: [
{
user_id: 1661871600,
details: {
height: 150,
age: 33,
work: 1015,
school: 10,
degree: 933
},
work: [
{
id: 500,
main: 'Doctor',
description: 'Ofto',
icon: '10d',
},
],
look: {
all: 100,
},
transport: {
speed: 0.62,
max_speed: 349,
},
visibility: 10000,
hair: {
type: 0.26,
},
date: '2022-08-30 15:00:00',
},
{
user_id: 324235256,
details: {
height: 110,
age: 25,
work: 101,
school: 110,
degree: 553
},
work: [
{
id: 500,
main: 'Software',
description: 'Programmer',
icon: '11d',
},
],
look: {
all: 2,
},
transport: {
speed: 1.2,
max_speed: 49,
},
visibility: 221,
hair: {
type: 5.6,
},
date: '2021-01-30 12:00:00',
},
{
user_id: 12353743,
details: {
height: 10,
age: 75,
work: 1,
school: 114,
degree: 3
},
work: [
{
id: 500,
main: 'Pension',
description: 'Architect',
icon: '1d',
},
],
look: {
all: 6,
},
transport: {
speed: 3.2,
max_speed: 29,
},
visibility: 21,
hair: {
type: 1.6,
},
date: '2020-01-30 12:00:00',
},
],
};
// main function
const fun =(ob, k , con)=>{
// recursive object function
const objectFun =(arr)=>{
for(y in arr){
if(typeof arr[y] === "object"){
objectFun(arr[y])
}else if(Array.isArray(arr[y])){
arrayFun(arr[y])
}else if(k.includes(y)){
temp[y] = arr[y]
}}}
// recursive array function
const arrayFun =(xx) =>{
const usersList = ob[xx].map((ar, i)=>{
objectFun(ar)
con.push(temp)
temp ={}
})}
// main access key for in loop
for(x in ob){
var temp = {}
arrayFun(x)
}
return con
}
console.log(fun(response , keys , []))
.as-console-wrapper { min-height: 100%!important; top: 0; }

Related

change the position of object in array inside other object

in given data every ingredient have its substitute option while I can
select any substitute option for example if I want to change masala
with its substitute output will change the position of substitute with
it's option and output should be given below
i want to replace masala with normal masala
i have to create a function who replace ingredient with it's substitute and interchange the position of both *
input
const oData = [
{ CurryName: 'Chiken', id: 0 },
{
ingredients: [
{
id: 1,
name: 'onion',
property: { color: 'yellow', Quantity: 'half KG', price: 120 },
subOption: [
{
id: 11,
name: 'redOnion',
property: { color: 'red', Quantity: '1 KG', price: 120 },
},
{
id: 12,
name: 'whiteOnion',
property: { color: 'white', Quantity: '2 KG', price: 120 },
},
],
},
{
id: 2,
name: 'oil',
property: { color: 'green', Quantity: 'half LT', price: 120 },
subOption: [
{
id: 21,
name: 'yellowOil',
property: { color: 'yellow', Quantity: '1 LT', price: 120 },
},
{
id: 22,
name: 'olivoOil',
property: { color: 'golden', Quantity: '2 LT', price: 120 },
},
{
id: 22,
name: 'CastrolOil',
property: { color: 'silk', Quantity: '2 LT', price: 170 },
},
],
},
{
id: 3,
name: 'masala',
property: { color: 'gray', Quantity: '1Tspoon', price: 30 },
subOption: [
{
id: 31,
name: 'garamMasala',
property: { color: 'Garam', Quantity: '2Tspoon', price: 30 },
},
{
id: 32,
name: 'chikenMasala',
property: { color: 'green', Quantity: ' 3Tspoon', price: 30 },
},
{
id: 33,
name: 'normalMasala',
property: { color: 'red', Quantity: '5Tspoon', price: 30 },
},
],
},
],
},
];
// in given data every ingredient have it's substitute option while i can select any supstitute option for example if i want to change masala with its substitute output will change the position of substitue with it's option and output should be given below
//i want to replace masala with normal masala
const output = [
{ CurryName: 'Chiken', id: 0 },
{
ingredients: [
{
id: 1,
name: 'onion',
property: { color: 'yellow', Quantity: 'half KG', price: 120 },
subOption: [
{
id: 11,
name: 'redOnion',
property: { color: 'red', Quantity: '1 KG', price: 120 },
},
{
id: 12,
name: 'whiteOnion',
property: { color: 'white', Quantity: '2 KG', price: 120 },
},
],
},
{
id: 2,
name: 'oil',
property: { color: 'green', Quantity: 'half LT', price: 120 },
subOption: [
{
id: 21,
name: 'yellowOil',
property: { color: 'yellow', Quantity: '1 LT', price: 120 },
},
{
id: 22,
name: 'olivoOil',
property: { color: 'golden', Quantity: '2 LT', price: 120 },
},
{
id: 22,
name: 'CastrolOil',
property: { color: 'silk', Quantity: '2 LT', price: 170 },
},
],
},
{
id: 33,
name: 'normalMasala',
property: { color: 'red', Quantity: '5Tspoon', price: 30 },
subOption: [
{
id: 31,
name: 'garamMasala',
property: { color: 'Garam', Quantity: '2Tspoon', price: 30 },
},
{
id: 32,
name: 'chikenMasala',
property: { color: 'green', Quantity: ' 3Tspoon', price: 30 },
},
{
id: 3,
name: 'masala',
property: { color: 'gray', Quantity: '1Tspoon', price: 30 },
}
],
},
],
},
];
console.log(output)
I suggest that define an element before 'subOption' like 'selectedOption' so you can change it more easily between them
{
selectedOption:{id: 33,
name: 'normalMasala',
property: { color: 'red', Quantity: '5Tspoon', price: 30 }},
subOption: [
{
id: 31,
name: 'garamMasala',
property: { color: 'Garam', Quantity: '2Tspoon', price: 30 },
},
{
id: 32,
name: 'chikenMasala',
property: { color: 'green', Quantity: ' 3Tspoon', price: 30 },
},
{
id: 3,
name: 'masala',
property: { color: 'gray', Quantity: '1Tspoon', price: 30 },
}
],
}
if you able to add 'selectedOption' you can use this code
let temp = oData[1].ingredients[3].subOption[3]
oData[1].ingredients[3].subOption[3].splice(3,1,oData[1].ingredients[3].selectedOption)
oData[1].ingredients[3].selectedOption=temp;
This solution may not be ideal because it changes the original data. But if you don't mind changing the original data, use this.
function swapIngredientMainSub(data, mainID, subID) {
const { ingredients } = data[1];
const targetIndex = ingredients.findIndex(({ id }) => id === mainID);
const { subOption, ...main } = ingredients[targetIndex];
const subIndex = subOption.findIndex(({ id }) => id === subID);
const sub = subOption[subIndex];
subOption[subIndex] = main;
ingredients[targetIndex] = { ...sub, subOption };
}
swapIngredientMainSub(oData, 3, 33);
console.log(JSON.stringify(oData) === JSON.stringify(output)); // true
Option 2:
function swapIngredientMainSub(data, subID) {
const { ingredients } = data[1];
const targetIndex = ingredients.findIndex(({ subOption }) =>
subOption.find(({ id }) => id === subID)
);
const { subOption, ...main } = ingredients[targetIndex];
const subIndex = subOption.findIndex(({ id }) => id === subID);
const sub = subOption[subIndex];
subOption[subIndex] = main;
ingredients[targetIndex] = { ...sub, subOption };
}
swapIngredientMainSub(oData, 33);
console.log(JSON.stringify(oData) === JSON.stringify(output)); // true
I don't know about d3 library that you have included in the tags, but you can use something like this:
const oData = [{
CurryName: 'Chiken',
id: 0
},
{
ingredients: [{
id: 1,
name: 'onion',
property: {
color: 'yellow',
Quantity: 'half KG',
price: 120
},
subOption: [{
id: 11,
name: 'redOnion',
property: {
color: 'red',
Quantity: '1 KG',
price: 120
},
},
{
id: 12,
name: 'whiteOnion',
property: {
color: 'white',
Quantity: '2 KG',
price: 120
},
},
],
},
{
id: 2,
name: 'oil',
property: {
color: 'green',
Quantity: 'half LT',
price: 120
},
subOption: [{
id: 21,
name: 'yellowOil',
property: {
color: 'yellow',
Quantity: '1 LT',
price: 120
},
},
{
id: 22,
name: 'olivoOil',
property: {
color: 'golden',
Quantity: '2 LT',
price: 120
},
},
{
id: 22,
name: 'CastrolOil',
property: {
color: 'silk',
Quantity: '2 LT',
price: 170
},
},
],
},
{
id: 3,
name: 'masala',
property: {
color: 'gray',
Quantity: '1Tspoon',
price: 30
},
subOption: [{
id: 31,
name: 'garamMasala',
property: {
color: 'Garam',
Quantity: '2Tspoon',
price: 30
},
},
{
id: 32,
name: 'chikenMasala',
property: {
color: 'green',
Quantity: ' 3Tspoon',
price: 30
},
},
{
id: 33,
name: 'normalMasala',
property: {
color: 'red',
Quantity: '5Tspoon',
price: 30
},
},
],
},
],
},
];
const selectIngredients = (obj, mainName, subName) => {
obj[1].ingredients.map(ingredient => {
if (ingredient.name === mainName) {
const optionIndex = ingredient.subOption.findIndex(element => element.name === subName);
if (optionIndex !== undefined) {
const {
id,
name,
property
} = ingredient;
ingredient.id = ingredient.subOption[optionIndex].id;
ingredient.name = ingredient.subOption[optionIndex].name;
ingredient.property = ingredient.subOption[optionIndex].property;
ingredient.subOption[optionIndex].id = id;
ingredient.subOption[optionIndex].name = name;
ingredient.subOption[optionIndex].property = property;
}
}
});
return obj;
};
console.log(selectIngredients(oData, "masala", "normalMasala"));

Get trees closer together

I am using tree layout and I have multiple trees (multiple roots).
How can I get the trees to be packed together and fill the empty space using layout.
Here is an example of my trees:
unpacked trees image
I want them to be more like this:
packed trees image
here is my current layout:
let myDiagram = new go.Diagram("myDiagramDiv",
{
layout: new go.TreeLayout({
treeStyle: go.TreeLayout.StyleLastParents,
arrangement: go.TreeLayout.ArrangementHorizontal,
compaction: go.TreeLayout.CompactionBlock,
// properties for most of the tree:
angle: 90,
layerSpacing: 35,
// properties for the "last parents":
alternateAngle: 90,
alternateLayerSpacing: 35,
alternateAlignment: go.TreeLayout.AlignmentBus,
alternateNodeSpacing: 20,
})
});
#HumanTarget has the right idea. Here's an example:
<script type="module">
import * as go from "../release/go-module.js";
import { ArrangingLayout } from "../extensionsJSM/ArrangingLayout.js";
import { PackedLayout } from "../extensionsJSM/PackedLayout.js";
const $ = go.GraphObject.make;
const myDiagram =
$(go.Diagram, "myDiagramDiv",
{
layout: $(ArrangingLayout,
{
primaryLayout: $(go.TreeLayout, { angle: 90 }),
arrangingLayout: $(PackedLayout, { spacing: 10 }),
})
});
myDiagram.nodeTemplate =
$(go.Node, "Auto",
$(go.Shape, { fill: "white" },
new go.Binding("fill", "color")),
$(go.TextBlock, { margin: 8 },
new go.Binding("text"))
);
myDiagram.model = new go.GraphLinksModel(
[
{ key: 1, text: "Alpha", color: "lightblue" },
{ key: 2, text: "Beta", color: "orange" },
{ key: 3, text: "Gamma", color: "lightgreen" },
{ key: 4, text: "Delta", color: "pink" },
{ key: 5, text: "Epsilon", color: "lightblue" },
{ key: 6, text: "Zeta", color: "orange" },
{ key: 7, text: "Eta", color: "lightgreen" },
{ key: 8, text: "Theta", color: "pink" },
{ key: 9, text: "Iota", color: "lightblue" },
{ key: 10, text: "Kappa", color: "orange" },
{ key: 11, text: "Lambda", color: "lightgreen" },
{ key: 12, text: "Mu", color: "pink" },
{ key: 13, text: "Nu", color: "lightblue" },
{ key: 14, text: "Xi", color: "orange" },
{ key: 15, text: "Omicron", color: "lightgreen" },
{ key: 16, text: "Pi", color: "pink" },
],
[
{ from: 1, to: 2 },
{ from: 1, to: 3 },
{ from: 4, to: 5 },
{ from: 4, to: 6 },
{ from: 6, to: 7 },
{ from: 8, to: 9 },
{ from: 9, to: 10 },
{ from: 11, to: 12 },
{ from: 13, to: 14 },
{ from: 13, to: 15 },
{ from: 13, to: 16 },
]);
</script>
Result:
But note that PackedLayout will treat each subtree as occupying a rectangular area, so it won't try to fit subtrees together where one or both of the subtrees has some empty space.

Convert json data to object

Good Day Developers!
I'm facing issue in JSON object received from MVC controller to AJAX success request.
The response which received is below.
[
{"name":"ERP Developer","value":2},
{"name":"Software Engineer","value":2},
{"name":"Dot Net Developer","value":2},
{"name":"Apex Developer","value":0},
{"name":"test","value":1}
]
But i want to make it like below.
{
"name": [
"ERP Developer",
"Software Engineer"
],
"Value": [
5,
10
]
}
Problem: Because i'm creating Bar chart using ECHARTS library but i want series name instead of number please see below image for reference.
function loadBarChart(data,title = "JobData",subtext = "Artistic Milliners") {
//var BarDBData = data;
var BarDBData = data;
//var BarDBData = JSON.parse('{"name":["ERP Developer","TEST"],"test":[5,10]}');
console.log(BarDBData);
var chartDom = document.getElementById('BarChart');
var myChart = echarts.init(chartDom);
var option;
option = {
title: {
text: title,
subtext: subtext
},
tooltip: {
trigger: 'axis'
},
toolbox: {
show: true,
feature: {
dataView: { show: true, readOnly: false },
magicType: { show: true, type: ['line', 'bar'] },
saveAsImage: { show: true }
}
},
calculable: true,
xAxis: [
{
type: 'category',
// prettier-ignore
//data: ["ERP Developer", "Software Engineer"],
data: BarDBData,
axisLabel: { interval: 0, rotate: 30 }
}
],
yAxis: [
{
type: 'value'
}
],
dataZoom: [
{
show: true,
start: 04,
end: 100
},
{
type: 'inside',
start: 44,
end: 100
},
{
show: true,
yAxisIndex: 0,
filterMode: 'empty',
width: 30,
height: '80%',
showDataShadow: false,
left: '93%'
}
],
series: [
{
name: "test",
type: 'bar',
data: BarDBData,
//data: [2.0, 4.9, 4, 9, 4],
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#83bff6' },
{ offset: 0.5, color: '#188df0' },
{ offset: 1, color: '#188df0' }
])
},
markPoint: {
data: [
{ type: 'max', name: 'Max' },
{ type: 'min', name: 'Min' }
]
}
}
]
};
option && myChart.setOption(option);
}
you can just map through array and extract values into another array
const result = {}
const arr = [{"name":"ERP Developer","value":2},{"name":"Software Engineer","value":2},{"name":"Dot Net Developer","value":2},{"name":"Apex Developer","value":0},{"name":"test","value":1}]
arr.forEach(row => {
for (let i in row) {
if (result[i]) {
result[i].push(row[i])
} else {
result[i] = [row[i]]
}
}
})
console.log(result)
Just reduce() it into the desired shape:
const response = [
{"name":"ERP Developer","value":2},
{"name":"Software Engineer","value":2},
{"name":"Dot Net Developer","value":2},
{"name":"Apex Developer","value":0},
{"name":"test","value":1}
];
const mapped = response.reduce(
(acc,x) => {
acc.name.push( x.name );
acc.Value.push( x.value );
return acc;
},
{ name: [], Value: [] }
);

Join and reduce arrays of objects

I need to join and order 2 arrangements, and I have not succeeded.
the first array contains "categories" of pokemons
and the second array contains pokemons and some data.
I need to join both arrays, sum the power value of each pokemon and show them in this way
expected result
[
{fire: 19000},
{ rock: 2100 },
{water: 1500}
]
1st array "cateogries or types"
const pokeTypes = [
{ uuid: 1, pokemonType: "fire" },
{ uuid: 2, pokemonType: "water" },
{ uuid: 3, pokemonType: "rock" }
];
2nd array pokemons
const pokemons = [
{
name: "geodude",
pokemonTypeId: 3,
power: 900,
},
{
name: "onix",
pokemonTypeId: 3,
power: 1200,
},
{
name: "squirtle",
pokemonTypeId: 2,
power: 100,
},
{
name: "seadra",
pokemonTypeId: 2,
power: 300,
},
{
name: "goldeen",
pokemonTypeId: 2,
power: 1100,
},
{
name: "charmander",
pokemonTypeId: 1,
power: 2000,
},
{
name: "charmeleon",
pokemonTypeId: 1,
power: 4000,
},
{
name: "charizard",
pokemonTypeId: 1,
power: 7000,
},
{
name: "magmar",
pokemonTypeId: 1,
power: 6000,
},
];
I started doing a reducer and was able to generate an array of objects grouped by pokemonTypeId, I couldn't continue after this...
I tried
function sortPokemons() {
result = pokemons.reduce(
(h, pokemons) =>
Object.assign(h, {
[pokemons.pokemonTypeId]: (h[pokemons.pokemonTypeId] || []).concat({
typeId: pokemons.pokemonTypeId,
}),
}),
{}
);
console.log(result);
}
console.log(sortPokemons());
thanks!
You can easily and efficiently achive the result using Map
const pokeTypes = [
{ uuid: 1, pokemonType: "fire" },
{ uuid: 2, pokemonType: "water" },
{ uuid: 3, pokemonType: "rock" },
];
const pokemons = [
{
name: "geodude",
pokemonTypeId: 3,
power: 900,
},
{
name: "onix",
pokemonTypeId: 3,
power: 1200,
},
{
name: "squirtle",
pokemonTypeId: 2,
power: 100,
},
{
name: "seadra",
pokemonTypeId: 2,
power: 300,
},
{
name: "goldeen",
pokemonTypeId: 2,
power: 1100,
},
{
name: "charmander",
pokemonTypeId: 1,
power: 2000,
},
{
name: "charmeleon",
pokemonTypeId: 1,
power: 4000,
},
{
name: "charizard",
pokemonTypeId: 1,
power: 7000,
},
{
name: "magmar",
pokemonTypeId: 1,
power: 6000,
},
];
const map = new Map();
pokemons.forEach((o) =>
map.has(o.pokemonTypeId)
? map.set(o.pokemonTypeId, map.get(o.pokemonTypeId) + o.power)
: map.set(o.pokemonTypeId, o.power)
);
const result = pokeTypes.map((o) => ({ [o.pokemonType]: map.get(o.uuid) }));
console.log(result);
/* This is not a part of answer. It is just to give the output fill height. So IGNORE IT */
.as-console-wrapper { max-height: 100% !important; top: 0; }
const pokeTypes = [
{ uuid: 1, pokemonType: "fire" },
{ uuid: 2, pokemonType: "water" },
{ uuid: 3, pokemonType: "rock" }
];
const pokemons = [
{
name: "geodude",
pokemonTypeId: 3,
power: 900,
},
{
name: "onix",
pokemonTypeId: 3,
power: 1200,
},
{
name: "squirtle",
pokemonTypeId: 2,
power: 100,
},
{
name: "seadra",
pokemonTypeId: 2,
power: 300,
},
{
name: "goldeen",
pokemonTypeId: 2,
power: 1100,
},
{
name: "charmander",
pokemonTypeId: 1,
power: 2000,
},
{
name: "charmeleon",
pokemonTypeId: 1,
power: 4000,
},
{
name: "charizard",
pokemonTypeId: 1,
power: 7000,
},
{
name: "magmar",
pokemonTypeId: 1,
power: 6000,
},
];
var data = pokeTypes.map(function(type) {
var res = {};
res[type.pokemonType] = pokemons.filter((item) => {
return item.pokemonTypeId === type.uuid;
}).reduce(function(sum, item) {
return sum + item.power;
}, 0);
return res;
});
console.log(data);
Can be achieved using simple immutable programming: just use array methods map() and reduce().
const pokeTypes = [
{ uuid: 1, pokemonType: "fire" },
{ uuid: 2, pokemonType: "water" },
{ uuid: 3, pokemonType: "rock" },
];
const pokemons = [
{
name: "geodude",
pokemonTypeId: 3,
power: 900,
},
{
name: "onix",
pokemonTypeId: 3,
power: 1200,
},
{
name: "squirtle",
pokemonTypeId: 2,
power: 100,
},
{
name: "seadra",
pokemonTypeId: 2,
power: 300,
},
{
name: "goldeen",
pokemonTypeId: 2,
power: 1100,
},
{
name: "charmander",
pokemonTypeId: 1,
power: 2000,
},
{
name: "charmeleon",
pokemonTypeId: 1,
power: 4000,
},
{
name: "charizard",
pokemonTypeId: 1,
power: 7000,
},
{
name: "magmar",
pokemonTypeId: 1,
power: 6000,
},
];
const totals = pokeTypes.map(({uuid, pokemonType}) => {
const total = pokemons.reduce((acc, {power, pokemonTypeId}) =>
pokemonTypeId === uuid ? acc + power : acc
, 0);
return { [pokemonType] : total };
});
console.log(totals);
And if you want to a nice clean object { fire: 19000, rock: 2100, water: 1500 }, which IMO is cleaner than array, replace the .map() with another .reduce():
const totals = pokeTypes.reduce((acc, {uuid, pokemonType}) => {
const total = pokemons.reduce((totalAcc, {power, pokemonTypeId})=>
pokemonTypeId === uuid ? totalAcc + power : totalAcc
, 0);
return {
...acc,
[pokemonType]: total,
}
}, {});

How to highlight the path between two nodes in CYTOSCAPE JS

i can create a graph using cytoscape js library . i am following the this tutorial and i implement like this.
CODE:
$(function(){ // on dom ready
$('#cy').cytoscape({
style: cytoscape.stylesheet()
.selector('node')
.css({
'content': 'data(id)'
})
.selector('edge')
.css({
'target-arrow-shape': 'triangle',
'width': 4,
'line-color': '#ddd',
'target-arrow-color': '#ddd'
})
.selector('.highlighted')
.css({
'background-color': '#61bffc',
'line-color': '#61bffc',
'target-arrow-color': '#61bffc',
'transition-property': 'background-color, line-color, target-arrow-color',
'transition-duration': '0.5s'
}),
elements: {
nodes: [
{ data: { id: 'a' } },
{ data: { id: 'b' } },
{ data: { id: 'c' } },
{ data: { id: 'd' } },
{ data: { id: 'e' } },
{ data: { id: 'f' } },
{ data: { id: 'g' } }
],
edges: [
{ data: { id: 'ab', weight: 1, source: 'a', target: 'b' } },
{ data: { id: 'ac', weight: 2, source: 'a', target: 'c' } },
{ data: { id: 'bd', weight: 3, source: 'b', target: 'd' } },
{ data: { id: 'be', weight: 4, source: 'b', target: 'e' } },
{ data: { id: 'cf', weight: 5, source: 'c', target: 'f' } },
{ data: { id: 'cg', weight: 6, source: 'c', target: 'g' } }
]
},
layout: {
name: 'breadthfirst',
directed: true,
roots: '#a',
padding: 5
},
ready: function(){
window.cy = this;
var bfs = cy.elements().bfs('#a', function(){}, true);
var i = 0;
var highlightNextEle = function(){
bfs.path[i].addClass('highlighted');
if( i < bfs.path.length ){
i++;
setTimeout(highlightNextEle, 1000);
}
};
// kick off first highlight
highlightNextEle();
}
});
}); // on dom ready
on my implementation i need to highlight the path between the nodes d and g.
How to find the path between the nodes and highlight them?
Using dijkstra algorithm method we can find the path between the nodes.
var dijkstra = cy.elements().dijkstra('#e',function(){
return this.data('weight');
},false);
var bfs = dijkstra.pathTo( cy.$('#i') );
Complete CODE :
$(function(){ // on dom ready
$('#cy').cytoscape({
style: cytoscape.stylesheet()
.selector('node')
.css({
'content': 'data(id)'
})
.selector('edge')
.css({
'target-arrow-shape': 'triangle',
'width': 4,
'line-color': '#ddd',
'target-arrow-color': '#ddd'
})
.selector('.highlighted')
.css({
'background-color': '#61bffc',
'line-color': '#61bffc',
'target-arrow-color': '#61bffc',
'transition-property': 'background-color, line-color, target-arrow-color',
'transition-duration': '0.5s'
}),
elements: {
nodes: [
{ data: { id: 'a' } },
{ data: { id: 'b' } },
{ data: { id: 'c' } },
{ data: { id: 'd' } },
{ data: { id: 'e' } },
{ data: { id: 'f' } },
{ data: { id: 'g' } },
{ data: { id: 'h' } },
{ data: { id: 'i' } }
],
edges: [
{ data: { id: 'ab', weight: 1, source: 'a', target: 'b' } },
{ data: { id: 'ac', weight: 2, source: 'a', target: 'c' } },
{ data: { id: 'bd', weight: 3, source: 'b', target: 'd' } },
{ data: { id: 'be', weight: 4, source: 'b', target: 'e' } },
{ data: { id: 'cf', weight: 5, source: 'c', target: 'f' } },
{ data: { id: 'cg', weight: 6, source: 'c', target: 'g' } },
{ data: { id: 'ah', weight: 7, source: 'a', target: 'h' } },
{ data: { id: 'hi', weight: 8, source: 'h', target: 'i' } }
]
},
layout: {
name: 'breadthfirst',
directed: true,
roots: '#a',
padding: 5
},
ready: function(){
window.cy = this;
var dijkstra = cy.elements().dijkstra('#e',function(){
return this.data('weight');
},false);
var bfs = dijkstra.pathTo( cy.$('#i') );
var x=0;
var highlightNextEle = function(){
var el=bfs[x];
el.addClass('highlighted');
if(x<bfs.length){
x++;
setTimeout(highlightNextEle, 500);
}
};
highlightNextEle();
}
});
}); // on dom ready
I you want to highlight all the possible paths
event.target- is the starting node
event.target.successors().animate({
style: { lineColor: 'red' }
});
Assuming you have picked two nodes and stored them in source_node and target_node, and you want to label everything in between with class 'path_element':
p = cy.elements().aStar({root: source_node, goal: target_node, directed: true}).path;
if (p) {
p.filter(function(i,x) { return x != source_node && x != target_node; })
.addClass('path_element');
p.edgesWith(p)
.addClass('path_element');
}

Categories