Transforming JSON based on inputs and outputs - javascript

Following is an object array that has a value v, its input i and output o.
var data = [
{
v: 1,
i: [],
o: [1, 2, 3]
},
{
v: 2,
i: [2],
o: [4, 5, 6]
]
},
{
v: 3,
i: [1, 4],
o: [7, 8]
},
{
v: 4,
i: [],
o: [3]
}
]
The final JSON structure is created by checking the input and outputs of each v, i.e. the parent child relations...
Final JSON structure..
[
{
v: 1,
children: [
{
v: 2
},
{
v: 3
}
]
},
{
v: 4
}
]
I tried by the following code, but it's not transforming the object array properly...
function checkForOutputs(outputs, groupedValueChainEntityLists) {
for (var i = 0; i < outputs.length; i++) {
for (var j = 0; j < groupedValueChainEntityLists[j].inputs.length; j++) {
var val_Chain = groupedValueChainEntityLists[j].inputs.map((item) => {
if (outputs[i].o === item.o) {
return groupedValueChainEntityLists[j];
}
});
return val_Chain;
}
}
}
function constructValueChainRelations(data) {
var valueChainArray = new Array();
var result = data.map((item) => {
if (item.i.length === 0) {
valueChainArray.push(item);
return checkForOutputs(item.o, data);
}
});
console.log(result);
}

I think that you are making this too difficult. Simply map the values.
var data = [{
v: 1,
i: [],
o: [1, 2, 3]
}, {
v: 2,
i: [2],
o: [4, 5, 6]
}, {
v: 3,
i: [1, 4],
o: [7, 8]
}, {
v: 4,
i: [],
o: [3]
}];
function transform(verticies, idProp, childProp) {
return verticies.map(function(vertex) {
return {
v: vertex[idProp],
children: vertex[childProp].filter(function(childVertex) {
return childVertex !== vertex[idProp];
}).map(function(childVertex) {
return {
v: childVertex
};
})
}
});
}
var transformed = transform(data, 'v', 'o');
document.body.innerHTML = '<pre>' + JSON.stringify(transformed, null, 4) + '</pre>';
Result
[{
"v": 1,
"children": [{
"v": 2
}, {
"v": 3
}]
}, {
"v": 2,
"children": [{
"v": 4
}, {
"v": 5
}, {
"v": 6
}]
}, {
"v": 3,
"children": [{
"v": 7
}, {
"v": 8
}]
}, {
"v": 4,
"children": [{
"v": 3
}]
}]

You could use some loops and a look up mechanism with this.
var data = [{ v: 1, i: [], o: [1, 2, 3] }, { v: 2, i: [2], o: [4, 5, 6] }, { v: 3, i: [1, 4], o: [7, 8] }, { v: 4, i: [], o: [3] }],
result = [];
data.forEach(function (a) {
if (!this[a.v]) {
this[a.v] = { v: a.v, children: [] };
result.push(this[a.v]);
}
a.o.forEach(function (b) {
var k = a.v + '|' + b;
if (a.v !== b && !this[k]) {
this[k] = { v: b };
this[a.v].children.push(this[k]);
}
}, this);
}, {});
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');

Here's another way that is working..
Sample Code
function populateChildrenRecursively(outputTypeId, valueChainEntities, parentValueChainEntity) {
for (var i = 0; i < valueChainEntities.length; i++) {
if (valueChainEntities[i].valueChainEntity.valueChainEntityId != parentValueChainEntity.valueChainEntity.valueChainEntityId && hasInput(outputTypeId, valueChainEntities[i].inputs)) {
parentValueChainEntity.valueChainEntity.items.push(valueChainEntities[i]);
if (valueChainEntities[i].outputs.length > 0) {
valueChainEntities[i].valueChainEntity.items = [];
for (var j = 0; j < valueChainEntities[i].outputs.length; j++) {
populateChildrenRecursively(valueChainEntities[i].outputs[j].outputTypeId, valueChainEntities, valueChainEntities[i]);
}
}
}
}
}
JSON Conversion

Related

How to paginate a SectionList in react-native

I have an array of object, which every object contain a section and a data;
const arr = [
{ section: "a", data: [1, 2] },
{ section: "b", data: [3, 4, 5, 6] },
{ section: "c", data: [7, 8, 9, 10, 11, 12, 13] }
];
Now I want to paginate it.
I need to display 4 item in one page.
So it would be like:
[
{page: 1, section: ['a', 'b'], data: [1, 2, 3, 4]}
{page: 2, section: ['b', 'c'], data: [5, 6, 7, 8]}
{page: 3, section: ['c'], data: [9, 10, 11, 12]}
{page: 4, section: ['c'], data: [13]}
]
Any help, I tried many ways but still could not solve.
My Efforts
const arr = [
{ title: "a", data: [1, 2] },
{ title: "b", data: [3, 4, 5, 6] },
{ title: "c", data: [7, 8, 9, 10, 11, 12, 13] }
];
let c = 0, na = [], ha = [];
for(let i = 0; i < arr.length; i++){
let ia = arr[i].data;
for(let k = 0; k < ia.length; k++){
na = [...na, [ arr[i].title, ia[k] ]];
// na = [...na, {[c]: {section: arr[i].title, data: ia[k]}}]; c++;
}
}
// console.log(JSON.stringify(na));
function chunk (arr, len) {
var chunks = [], i = 0, n = arr.length;
while (i < n) {
chunks.push(arr.slice(i, i += len));
}
return chunks;
}
const resCh = chunk(na, 3);
console.log(resCh);
let finalArr = [];
for(let i = 0; i< resCh.length; i++){
let nstd = resCh[i], finalObj = {};
nstd.reduce( (t, s) => {
if(t[0] === s[0]) {
if(finalObj[t[0]]){
finalObj = {
...finalObj,
[t[0]]: [
...finalObj[t[0]],
t[1], s[1]
]
}
}else {
finalObj = {
...finalObj,
[t[0]]: [t[1], s[1]]
}
}
}else {
if(finalObj[t[0]]){
finalObj = {
...finalObj,
[t[0]]: [
...finalObj[t[0]],
t[1]
]
}
}else {
finalObj = {
...finalObj,
[t[0]]: [ t[1] ]
}
}
}
return s;
});
finalArr.push(finalObj);
}
console.log(finalArr);
You could do something like this:
const arr = [
{ section: "a", data: [1, 2] },
{ section: "b", data: [3, 4, 5, 6] },
{ section: "c", data: [7, 8, 9, 10, 11, 12, 13] }
];
const fillRange = (start, end) => {
return Array(end - start + 1).fill().map((item, index) => start + index);
};
let result = [];
let j = 0
let maxData = Math.max(...arr.map(x => x.data).flat(2))
for (let i = 0; i < 4; i++) {
if (j === 0) j = i + 1;
else j = j + 4;
const finalData = fillRange(j, j + 3).filter(x => x <= maxData);
let section = [];
arr.forEach(val => {
if(val.data.some(v => finalData.includes(v))) section.push(val.section);
});
let resObj = {page: i + 1, section: section, data: finalData}
result.push(resObj)
}
console.log(result)
Explanation:
With fillRange function I create arrays of consecutive numbers 4 by 4 (like [1,2,3,4][5,6,7,8]...). These values have an upper bound = max value found in all data arrays (fillRange(j, j + 3).filter(x => x <= maxData));
Find the section for which data includes these numbers;
Crete result object with all data found before and push it in result array.

Problem with using for-in/of when returning an object in a function

I just got the result "[object Object]'s score is 0" printed on the terminal.
The result 27 was all fine until I separated the function into a return object.
How do I get 27 if I have to return an object?
How do I get "alex" printed on the console.log instead of [object Object]?
const alex = {
first: [1, 2, 9, 8],
second: [3],
third: [0, 0, 0, 1, 3]
};
const gordon = {
first: [3],
second: [2, 2, 4, 5, 6, 6, 7, 8]
}
function createPlayer(object) {
let score = 0;
return {
add: function() {
for (const key in object) {
for (const item in object[key]) {
score += object[key][item]
}
}
},
result: function() {
return `${object}\'s score is ${score}`
}
}
}
createPlayer(alex).add()
console.log(createPlayer(alex).result())
const alex = {
first: [1, 2, 9, 8],
second: [3],
third: [0, 0, 0, 1, 3]
};
const gordon = {
first: [3],
second: [2, 2, 4, 5, 6, 6, 7, 8]
}
function createPlayer(object, name) {
let score = 0;
return {
add: function() {
for (const key in object) {
for (const item in object[key]) {
score += object[key][item]
}
}
return this; // <<<<<
},
result: function() {
return `${name}\'s score is ${score}`
}
}
}
console.log(createPlayer(alex, 'Alex').add().result())
You would not show alex for an object named alex
You might mean this
const alex = {
Name: "Alex",
first: [1, 2, 9, 8],
second: [3],
third: [0, 0, 0, 1, 3]
};
const gordon = {
Name: "Gordon",
first: [3],
second: [2, 2, 4, 5, 6, 6, 7, 8]
}
function createPlayer(object) {
let score = 0;
return {
add: function() {
for (const key in object) {
if (key!=="Name") {
for (const item in object[key]) {
score += object[key][item]
}
}
}
},
result: function() {
return `${object.Name}\'s score is ${score}`
}
}
}
const player1 = createPlayer(alex)
player1.add()
console.log(player1.result())

Group the objects in javascript

Need to check does "X" or "O" has more occurrences. The values of the array possibilities should be compared against the row value of the moves array. As we find the value of the occurrence reaches 3, we need to stop the iteration.
const possibilities = [
[0, 1, 2],
[3, 4, 5],
...
];
const moves = [{
"row": 0,
"type": "X",
},
{
"row": 1,
"type": "O",
},
{
"row": 2,
"type": "O",
},
{
"row": 3,
"type": "X",
},
{
"row": 4,
"type": "O",
},
{
"row": 5,
"type": "X",
}];
Code as follows:
let count = 0;
possibilities.forEach((possibility) => {
let type = null;
for (let index = 0; index < possibility.length; index++) {
console.log(possibility[index], "index")
for (let j = 0; j < moves; j++) {
if (moves[j].row === possibility[index]) {
console.log(moves[j], "j")
if (type === null) {
type = moves[j].type;
} else if (type === moves[j].type) {
++count;
} else {
type = null;
count = 0;
}
}
}
}
})
This code may help you.
If this did not work. Please write a comment. So I can edit my answer.
This code is not fully optimized!! But I can do that if the code works for you.
let counts = {}
for(const possibility of possibilities) {
for(const move of moves) {
if(possibility.includes(move.row)) {
if(!(move.type in counts)) counts[move.type] = 0
counts[move.type]++
}
}
}
console.log(counts)
let heightsValue = -1
let heightsType = '-'
for(const type in counts) {
if(counts[type] > heightsValue) {
heightsType = type
heightsValue = counts[type]
}
}
console.log(heightsType)
If I understand correctly, you want to iterate over possibilities to see if at least 3 of their moves are type 'X'.
Predispositions...
const possibilities = [
[0, 1, 2], // ['X', 'O', 'O'] -> false
[3, 4, 5], // ['X', 'O', 'X'] -> false
[0, 3, 5], // ['X', 'X', 'X'] -> true
];
const moves = [{
"row": 0,
"type": "X",
}, {
"row": 1,
"type": "O",
}, {
"row": 2,
"type": "O",
}, {
"row": 3,
"type": "X",
}, {
"row": 4,
"type": "O",
}, {
"row": 5,
"type": "X",
}];
match moves
let result = possibilities.map((possibility) =>
possibility.map((row) => moves.find(r => r.row === row).type)
);
// [ [ 'X', 'O', 'O' ], [ 'X', 'O', 'X' ], [ 'X', 'X', 'X' ] ]
find out how many Xs
result = result.map((posibility) =>
posibility.filter(moveType => moveType === 'X').length
);
// [1, 2, 3]
compare there at at least 3 Xs
result = result.map((xMoves) => xMoves >= 3);
// [false, false, true]
All in one
let result = possibilities.map((possibility) =>
possibility.map((row) => moves.find(r => r.row === row).type)
.filter(moveType => moveType === 'X')
.length >= 3
);
// [false, false, true]
The 3rd values in possibilities (possibilities[2] is the winner)

sheetjs xlsx, How to write merged cells?

I need to create a xlsx with merged cells using sheetjs.
data:
[
{
"id": "nick",
"items": [
{
"name": "ball"
},
{
"name": "phone"
}
]
},
{
"id": "jack",
"items": [
{
"name": "pen"
},
{
"name": "doll"
}
]
}
]
My code:
var ws = XLSX.utils.json_to_sheet(data);
var wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, "");
var wbout = XLSX.write(wb, {bookType:'xlsx', type:'array'});
saveAs(new Blob([wbout],{type:"application/octet-stream"}), filename + ".xlsx");
The result I want to get:
How do I get this result?
... Thank you
const merge = [
{ s: { r: 1, c: 0 }, e: { r: 2, c: 0 } },{ s: { r: 3, c: 0 }, e: { r: 4, c: 0 } },
];
ws["!merges"] = merge;
Use this code for merge A2:A3 ({ s: { r: 1, c: 0 }, e: { r: 2, c: 0 } })
and A4:A5 ({ s: { r: 3, c: 0 }, e: { r: 4, c: 0 } })
Here s = start, r = row, c=col, e= end

javascript several corresponding array reducing/sumup

What is the cleanest way to reduce those array ?
data = {
id: [1, 1, 1, 3, 3, 4, 5, 5, 5, ...]
v: [10,10,10, 5, 10 ...]
}
For each id there is a v corresponding. What I want is sum up v for each id. In this example the result should be
data = {
id: [1, 3, 4, 5, ...]
v: [30, 15, ...]
}
I would go for the Array.prototype.reduce() ,simple and elegant solution
var ids = [1, 1, 1, 3, 3, 3, 3, 4, 5, 6, 6, 6],
v = [10, 10, 10, 5, 10, 10, 10, 404, 505, 600, 60, 6],
data = {};
data.v = [];
data.ids = ids.reduce(function(a, b, index) {
if (a.indexOf(b) < 0) a.push(b);
if (!data.v[a.indexOf(b)]) data.v[a.indexOf(b)] = 0;
data.v[a.indexOf(b)] += v[index];
return a;
}, []);
https://jsfiddle.net/2ssbngLr/
One way of doing this, given two arrays of equal length would be to map/reduce them:
const ids = [1, 1, 1, 3, 3];
const vs = [10,10,10,5,10];
const reduced = ids
.map((val, i) => ({ id: val, value: vs[i] }))
.reduce((agg, next) => {
agg[next.id] = (agg[next.id] || 0) + next.value;
return agg;
}, {});
console.log(reduced);
// Object {1: 30, 3: 15}
Working example: https://jsfiddle.net/h1o5rker/1/
I think it can be accomplished with reduce
var data = {
id: [1, 1, 1, 3, 3],
v: [10, 10, 10, 5, 10]
}
var sumsObjs = data.v.reduce(function(sum, val, index) {
var id = data.id[index];
if (sum[id] !== undefined) {
sum[id] = sum[id] + val;
} else {
sum[id] = val;
}
return sum;
}, {});
console.log(sumsObjs);
<script src="https://getfirebug.com/firebug-lite-debug.js"></script>
var data={
id: [1,1,1,10,123,4531],
v:[123,123,53,223,11,11,11]
},
_v = data.v, vinit;
document.write(data.v+'<br>');
for(var i=0;i<_v.length;i++){
vinit = _v[i];
for(var j=i+1; j<=_v.length;j++){
if(_v[j]===vinit){
delete _v[j];
}
}
};
document.write(data.v);
var data={
id: [1,1,1,10,123,4531],
v:[123,123,53,223,11,11,11,...]
},
_v = data.v, vinit;
for(var i=0;i<_v.length;i++){
vinit = _v[i];
for(var j=i+1; j<=_v.length;j++){
if(_v[j]===vinit){
delete _v[j];
}
}
}
the above code is just for the v but you can simultaneously reduce the repeating elements for id too by introducing some more variables
in the snippet you can see that there are the extra commas in the second line which shows that those elements were deleted
If the ids are always in order, a simple for loop can solve it. There is no need to get overly complicated.
data = {
id: [1, 1, 1, 3, 3, 4, 5, 5, 5],
v: [10, 10, 10, 5, 10, 1, 2, 3, 4]
};
var result = {
id: [],
v: []
};
(function() {
var ids = data.id,
vals = data.v,
lastId = ids[0],
runningTotal = vals[0];
for (var i = 1; i < ids.length; i++) {
if (lastId === ids[i]) {
runningTotal += vals[i];
}
if (lastId !== ids[i] || i + 1 === ids.length) {
result.id.push(lastId);
result.v.push(runningTotal);
lastId = ids[i];
runningTotal = vals[i];
}
}
}());
console.log(result);
Some people have posted some good solutions so far, but I haven't really seen one that does exactly what you're looking for. Here is one that takes your specific object and returns an object of the same format, but meeting your requirements and reduced.
// Your data object
data = {
id: [1, 1, 1, 3, 3],
v: [10,10,10, 5, 10]
}
// Assuming obj consists of `id` and `v`
function reduce(obj){
// We create our reduced object
var reducedObj = {
id: [],
v: []
}
// Next we create a hash map to store keys and values
var map = {};
for(var i=0; i<obj.id.length; ++i){
// If this key doesn't exist, create it and give it a value
if(typeof map[parseInt(obj.id[i])] === 'undefined'){
map[parseInt(obj.id[i])] = 0;
}
// Sum all of the values together for each key
map[parseInt(obj.id[i])] += parseInt(obj.v[i]);
}
// Now we map back our hashmap to our reduced object
for(var ele in map){
reducedObj.id.push(ele);
reducedObj.v.push(map[ele]);
}
// Return our new reduced object
return reducedObj;
}
var myReducedObject = reduce(data);
console.log(myReducedObject);
Working Fiddle
This is a solution for ordered id with Array.prototype.reduce().
var data = {
id: [1, 1, 1, 3, 3, 4, 5, 5, 5],
v: [10, 10, 10, 5, 10, 7, 8, 10, 13]
},
result = { id: [], v: [] };
data.id.reduce(function (r, a, i) {
if (r === a) {
result.v[result.v.length - 1] += data.v[i];
} else {
result.id.push(a);
result.v.push(data.v[i]);
}
return a;
}, -1);
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
Or a in situ version
var data = {
id: [1, 1, 1, 3, 3, 4, 5, 5, 5],
v: [10, 10, 10, 5, 10, 7, 8, 10, 13]
};
void function (d) {
var i = 1;
while (i < d.id.length) {
if (d.id[i - 1] === d.id[i]) {
d.id.splice(i, 1);
d.v[i - 1] += d.v.splice(i, 1)[0];
continue;
}
i++;
}
}(data);
document.write('<pre>' + JSON.stringify(data, 0, 4) + '</pre>');

Categories

Resources