Javascript manipulating json issue - javascript

[
{
"timing": [
{
"zone": 18.8
},
{
"zone": 17.06,
},
{
"zone": 16.6
},
]
},
{
"timing": [
{
"zone": 12.6,
},
{
"zone": 14.6,
}
]
},
{
"timing": [
{
"zone":19.06,
},{
"zone": 8.06,
}
]
}
]
Here i am trying to work manipulate with one json data using javascript.
But, I am not able to think any approach how to achive that.
I am expecting below json. It give zone1, zone2, zone3 as per the zone any it will be dynamically
Please have a look to below json.
[
{
"zone1": [18.8, 12.6, 19.06 ]
},{
"zone2": [17.06, 14.6, 8.06]
}, {
"zone3":[16.6]
}
]
This is the output of json how it should look like.
Please have a look

You can use reduce and forEach
Loop through data, set OP's initial value as an object
Loop through timing property of each element, check if the zone + index + 1 exists in op or not, if exists push zone to that key else initialise new key
let data = [{"timing": [{"zone": 18.8},{"zone": 17.06,},{"zone": 16.6},]},{"timing": [{"zone": 12.6,},{"zone": 14.6,}]},{"timing": [{"zone": 19.06,}, {"zone": 8.06,}]}]
let final = data.reduce((op, { timing }) => {
timing.forEach(({ zone }, i) => {
let key = `zone${ 1 + i }`
op[key] = op[key] || []
op[key].push(zone)
})
return op
}, {})
console.log(final)
// If you need final output to be array of object just use entries and map to build a desired output
console.log(Object.entries(final).map(([k,v])=>({[k]:v})))

Here's a possible solution
var data = [{
"timing": [{
"zone": 18.8
},
{
"zone": 17.06,
},
{
"zone": 16.6
},
]
},
{
"timing": [{
"zone": 12.6,
},
{
"zone": 14.6,
}
]
},
{
"timing": [{
"zone": 19.06,
}, {
"zone": 8.06,
}]
}
];
// Calculate the total number of zones
var totalZones = 0;
for (let i = 0; i < data.length; i++) {
const currZones = data[i].timing.length;
if (currZones > totalZones) totalZones = currZones;
}
console.log(totalZones);
// Create the final Array
var result = new Array(totalZones);
for (let i = 0; i < totalZones; i++) {
result[i] = {
zone: []
}
}
// Populate the final array with values
for (let i = 0; i < totalZones; i++) {
for (let j = 0; j < data.length; j++) {
let currTiming = data[j].timing[i];
if (currTiming !== undefined) {
let currZone = data[j].timing[i].zone;
if (currZone !== undefined) {
result[i].zone.push(currZone);
}
}
}
}
console.log(result);

1) Gather all zone values into one array of array
2) Calculate max rows needed for zones
3) Have a simple for-loop till max rows and use shift and push methods.
const data = [
{
timing: [
{
zone: 18.8
},
{
zone: 17.06
},
{
zone: 16.6
}
]
},
{
timing: [
{
zone: 12.6
},
{
zone: 14.6
}
]
},
{
timing: [
{
zone: 19.06
},
{
zone: 8.06
}
]
}
];
const zones = data.map(time => time.timing.map(z => z.zone));
const rows = zones.reduce((rows, arr) => Math.max(rows, arr.length), 0);
const all = [];
for (let index = 1; index <= rows; index++) {
const res = [];
zones.forEach(zone => zone.length > 0 && res.push(zone.shift()));
all.push({ [`zone${index}`]: res });
}
console.log(all);

const input = [ {"timing": [{"zone": 18.8},{"zone": 17.06,},{"zone": 16.6},]},{"timing": [{"zone": 12.6,},{"zone": 14.6,}]},{"timing": [{"zone":19.06,},{"zone": 8.06,}]}]
var data = input.map(t => t.timing.map(u => u.zone));
var output = data[0].map((col, i) => data.map(row => row[i])).map((item, index) => {res = {}; res["zone"+(index+1)] = item.filter(t => t!==undefined); return res});
console.log(output);

Not the shortest, but it's very readable.
var json = [{"timing": [{"zone": 18.8},{"zone": 17.06,},{"zone": 16.6},]},{"timing": [{"zone": 12.6,},{"zone": 14.6,}]},{"timing": [{"zone": 19.06,}, {"zone": 8.06,}]}];
// index 0 is zone1, index 1 is zone2, index 2 is zone3, and so on ...
var zones = [];
// Loop through each 'timing' object
json.forEach(function(timingObject) {
var timing = timingObject['timing'];
// loop through each 'zone' in the given 'timing' object
timing.forEach(function(zoneObject, index) {
var zone = zoneObject['zone'];
// if the zone exists in the zones[] defined above
// add the current zone to its place
//
// if not (else), we have to add the array for the
// current index, then add the value of the current zone.
if(zones[index]) {
zones[index]['zone' + (index + 1)].push(zone);
} else {
zones.push({ ['zone' + (index + 1)]: [zone]})
}
});
});
console.log(zones);

Related

How to classify arrays and form new arrays

In my project, I need to classify an array and convert it to another type of array.
The difficulty I encountered was that there was no way to use concise and efficient execution. The following are my input and output:
const input = [{
"type": 1,
"color": "Red(268)"
},
{
"type": 1,
"color": "Blue(583)"
},
{
"type": 2,
"color": "Blue(185)"
},
{
"type": 4,
"color": "Red(326)"
},
{
"type": 4,
"color": "Blue(967)"
},
{
"type": 5,
"color": "Red(863)"
}
]
const output = [
"Type 1: Red(268), Blue(583)",
"Type 2: Blue(185)",
"Type 4: Red(326), Blue(967)",
"Type 5: Red(863)"
]
The following is my method. I use the set() to find out the number of types, and then use for loop to convert it into a string and push into the array, but it cannot be executed continuously, so my function cannot get the correct result, and it is not efficient.
this.ty = 1;
this.result = [];
const set = new Set();
const length = input.filter(item => !set.has(item.type) ? set.add(item.type) : false).length + 1;
for (let i = 1; i < length; i++) {
const temp = input.filter(x => {
return x.type === ty;
})
if (temp.length < 2) {
this.result.push(`Type ${ty}: ${temp[0].color}`);
} else {
this.result.push(`Type ${ty}: ${temp[0].color}, ${temp[1].color}`);
}
this.ty = i + 1;
}
This problem has troubled me for a long time. Can someone provide an easier way to convert this array? Thank you for your help.
const input = [{
"type": 1,
"color": "Red(268)"
},
{
"type": 1,
"color": "Blue(583)"
},
{
"type": 2,
"color": "Blue(185)"
},
{
"type": 4,
"color": "Red(326)"
},
{
"type": 4,
"color": "Blue(967)"
},
{
"type": 5,
"color": "Red(863)"
}
]
console.log('input', input);
this.ty = 1;
this.result = [];
const set = new Set();
const length = input.filter(item => !set.has(item.type) ? set.add(item.type) : false).length + 1;
for (let i = 1; i < length; i++) {
const temp = input.filter(x => {
return x.type === ty;
})
if (temp.length < 2) {
this.result.push(`Type ${ty}: ${temp[0].color}`);
} else {
this.result.push(`Type ${ty}: ${temp[0].color}, ${temp[1].color}`);
}
this.ty = i + 1;
}
console.log('result', this.result);
// output
/* const output = [
"Type 1: Red(268), Blue(583)",
"Type 2: Blue(185)",
"Type 4: Red(326), Blue(967)",
"Type 5: Red(863)"
] */
You can use the Array.reduce() function to iterate your array and construct a new object.
const input = [{
"type": 1,
"color": "Red(268)"
},
{
"type": 1,
"color": "Blue(583)"
},
{
"type": 2,
"color": "Blue(185)"
},
{
"type": 4,
"color": "Red(326)"
},
{
"type": 4,
"color": "Blue(967)"
},
{
"type": 5,
"color": "Red(863)"
}
];
const mappedInput = input.reduce((grouped, {
type,
color
}) => {
if (!grouped.hasOwnProperty(type)) {
grouped[type] = `Type ${type}: ${color}`;
} else {
grouped[type] += `, ${color}`;
}
return grouped;
}, {});
console.log(Object.values(mappedInput));
We use an object to provide efficient key lookup and at the end, retrieve just the array of strings that we need.
You could reduce over the array to create an object that uses the type as a key and an array as a value, pushing new instances into the array with each iteration.
Then map over the Object.entries to produce a new array of strings.
const input = [{"type":1,"color":"Red(268)"},{"type":1,"color":"Blue(583)"},{"type":2,"color":"Blue(185)"},{"type":4,"color":"Red(326)"},{"type":4,"color":"Blue(967)"},{"type":5,"color":"Red(863)"}];
const out = input.reduce((acc, c) => {
const [ key, value ] = Object.values(c);
acc[key] = acc[key] || [];
acc[key].push(value);
return acc;
}, {});
const result = Object.entries(out).map(([key, value]) => {
return `Type ${key}: ${value.join(', ')}`
});
console.log(result);
Here's a simple, functional solution:
// Get list of unique input types
const types = Array.from(new Set(input.map(x => x.type)));
// Map over unique types, filter for matching inputs, yield all colors
const output = types.map(type => `Type ${type}: ${input.filter(x => x.type == type).map(x => x.color).join(', ')}`);
This is the Dynamic Solution for your problem.
let output = input.map(d => {
let k = Object.keys(d);
let v = Object.values(d)
let text = '';
for (var i in k) {
text += `${k[i]}: ${v[i]}, `
}
text = text.substring(0, text.length - 1);
return text })

Why does my plain JS loop not sum values to populate a new object?

I have an object which contains an array of ~130 objects which again have a field called orderProfit.
I now try to create a new object and populate it with the (chronological) sum of orderProfit.
Input (sample figures):
[{
"trades": [
{
"fields": {
"orderProfit": "100.000,00",
[...]
},
},
{
"fields": {
"orderProfit": "-500,00",
[...]
}
},
{
"fields": {
"orderProfit": "1.500,00",
[...]
}
},
[...]
}]
Desired output as array:
balanceByTrades = [100.000, 99.500, 101.000, ..., ]
Current attempt:
var balanceByTrades = [];
for (var i = 0; i < trades.length; i++) {
trades[i].fields.orderProfit = parseFloat(trades[i].fields.orderProfit);
// typeof returns number
if (i == 0) {
balanceByTrades[i] = trades[i].fields.orderProfit
} else {
balanceByTrades[i] = trades[i].fields.orderProfit + trades[i-1].fields.orderProfit
}
}
Which outputs
balanceByTrades = [100.000,00, -500,00, 1.500,00]
So why it doesn't sum?
When you need to parse a string to a number, don't use thousands separators, and to denote a decimal value, use a decimal point .
Remove all .s, and then replace the , with a .:
const arr = [{
"fields": {
"orderProfit": "100.000,00",
}
}, {
"fields": {
"orderProfit": "-500,00",
}
}, {
"fields": {
"orderProfit": "1.500,00",
}
}];
const orderProfits = arr.map(({ fields }) => fields.orderProfit);
let currentBalance = 0;
const balanceByTrades = orderProfits.map((profitStr) => {
const num = Number(
profitStr.replace(/\./g, '').replace(',', '.')
);
currentBalance += num;
return currentBalance;
});
console.log(balanceByTrades);

how do i use unique value in object overall

i have this API call, where i want to return the 3 highest and the 3 lowest "totalScore"'s in my object.
this is my function
app.get('/getTopThree', (req, res) => {
let store = Store.find({}, 'name _id', function (error, response) {
}).sort({_id:-1})
store.then(stores => {
let output = {}
function delay() {
return new Promise(function (resolve, reject) {
stores.map(async store => {
var j = 0
await Rate.find({
"storeId": store._id
},
'rate date', function(error, response) {
totalArray = [];
response.filter(function(el) {
totalArray.push(el.rate);
});
sumOfVotes = totalArray.reduce((a, b) => a + b, 0);
totalScore = Math.round(sumOfVotes / totalArray.length * 33.33);
var counts = {};
for (var i = 0; i < totalArray.length; i++) {
var num = totalArray[i];
counts[num] = counts[num] ? counts[num] + 1 : 1;
}
var finalStore = {
"totalScore": totalScore
}
output[j++] = finalStore;
})
})
setTimeout(function () {
resolve(store)
}, 1000)
})
}
delay().then(finalStore => {
console.log(finalStore)
console.log(output)
res.send({
"store": {
"name": finalStore,
"score": output
}
})
})
})
})
and this is my output
{
"store": {
"Klaregade": {
"name": "Klaregade",
"totalScore": 93
},
"Overgade": {
"name": "Overgade",
"totalScore": 67
}
}
}
So what i want is to loop though this object and return the 3 highest as
store: { "highest": output.highest, "lowest": output.lowest" }
can anyone help me with doing that, the problem is every returned value in my object has an unique name in the start ("klaregade" and "overgade")
how do i loop though them and take the higest and lowest value?
Thanks in advance.
Here is an example of working solution:
const output = {
"store": {
"Klaregade": {
"name": "Klaregade",
"totalScore": 93
},
"Overgade": {
"name": "Overgade",
"totalScore": 1
},
"Overgade2": {
"name": "Overgade2",
"totalScore": 412
},
"Overgade3": {
"name": "Overgade3",
"totalScore": 32
},
"Overgade4": {
"name": "Overgade4",
"totalScore": 67
}
}
}
const sorted = Object.values(output.store).sort((a, b) => b.totalScore - a.totalScore);
const store = {
highest: sorted.slice(0, 3),
lowest: sorted.slice(-3),
};
You have to keep in mind that you'll get trimmed results when array.length < 3
I found an solution for this.
what i did was instead of an object i made output to an array. and then pushed finalStore into the array.
and then in .delay.then() i made an for loop on my output
delay().then(finalStore => {
console.log(output)
for (var t = 0; t < output.length; t++) {
output.push({
"name": output[t].name,
"score": output[t].totalScore
})
}
res.send(output)
})
like this

How to solve this without using three nested for loops

I have an array of objects something like this
var data = [{"2017-09-13":{date_time:"2017-09-13",value:"20"}},{"2017-09-13":{date_time:"2017-09-13",value:"22"}},{"2017-09-15":{date_time:"2017-09-15",value:"25"}},{"2017-09-15":{date_time:"2017-09-15",value:"30"}},{"2017-09-16":{date_time:"2017-09-16",value:"10"}}];
I have an array of dates like this
var dates = ["2017-09-13","2017-09-15"];
I want to modify the data array in such a way that it only contains the days mentioned in the dates array. I have tried something like this
var date = [];
for (var i = 0; i < data.length; i++) {
for (var j = 0; j < dates.length; j++) {
for (key in data[i]) {
if (dates[j] == key) {
date.push(data[i])
}
}
}
}
And it gives me the required result. However this is not efficient and is lagging the application. Is there any efficient way to go about it?
EDIT: Updated the correct data structure
const data = [
{
"2017-09-13": {
"date_time": "2017-09-13",
"value": "20"
}
},
{
"2017-09-13": {
"date_time": "2017-09-13",
"value": "22"
}
},
{
"2017-09-15": {
"date_time": "2017-09-15",
"value": "25"
}
},
{
"2017-09-15": {
"date_time": "2017-09-15",
"value": "30"
}
},
{
"2017-09-16": {
"date_time": "2017-09-16",
"value": "10"
}
}
];
const dates = ["2017-09-13", "2017-09-15"];
const datesSet = new Set(dates);
const filteredData = data.filter(item => datesSet.has(Object.keys(item)[0]));
console.log(filteredData);
Consider removing the use of dates as keys, as they seem to be redundant information:
const data = [
{
"date_time": "2017-09-13",
"value": "20"
},
{
"date_time": "2017-09-13",
"value": "22"
},
{
"date_time": "2017-09-15",
"value": "25"
},
{
"date_time": "2017-09-15",
"value": "30"
},
{
"date_time": "2017-09-16",
"value": "10"
}
];
const dates = ["2017-09-13", "2017-09-15"];
const datesSet = new Set(dates);
const filteredData = data.filter(item => datesSet.has(item.date_time));
console.log(filteredData);
Your datastructure is ugly. You will always need two loops to iterate it. However, we could set up a more elegant datastructure ( aka a Map), which we can access more easily:
const days = new Map();
for(const obj of data){
for(day in obj){
if( days.has(day) ){
days.get(day).push( obj[day] );
} else {
days.set(day, [ obj[day] ]);
}
}
}
After the Map is created, you can simply do:
days.get("2017-09-13")
to get an array of objects with datetime/values. That can be iterated easily:
days.get("2017-09-13").forEach( ({value}) => {
console.log(value);
});
Or getting multiple dates:
const result = new Map(
dates.map(date => [date, days.get( date )] )
);
console.log( [...result] );
and data only:
const result = [];
dates.forEach(date => result.push(...days.get(date)));
Here is a solution with only two for loops.
var data = [{'2017-09-13':{date_time:"2017-09-13",value:"20"}},{'2017-09-13':{date_time:"2017-09-13",value:"22"}},{'2017-09-15':{date_time:"2017-09-15",value:"25"}},{'2017-09-15':{date_time:"2017-09-15",value:"30"}},{'2017-09-16':{date_time:"2017-09-16",value:"10"}}];
var date = [];
for (var i = 0; i < data.length; i++) {
for (key in data[i]) {
if (date.indexOf(key) === -1) {
date.push(key);
}
}
}
console.log(date);
var dataByDate = { };
for (var i = 0; i < data.length; i++) {
for (var j in data[i])
dataByDate[j] = dataByDate[j] || true;
}
Converts the data to
{ '2017-09-13': true, '2017-09-15': true, '2017-09-16': true }
Then you can do
for (var i in dataByDate) { ... }

How to convert array of object into an array of object with different format?

I'm having an array of object,in which I'm storing the billkey and billvalue as attributes. I want billkey to be the key and billvalue to be the value of that particular key.
var log=[
{
billkey:"Name",
billvalue:"ABC"
},
{
billkey:"Department",
billvalue:"Computer"
}
{
billkey:"Name",
billvalue:"XYZ"
},
{
billkey:"Department",
billvalue:"Electrical"
}];
And I want to convert it into this format:
var log=[
{
Name:"ABC",
Department:"Computer"
},
{
Name:"XYZ",
Department:"Electrical"
}];
How about this simple solution. Hope it helps!
var log=[
{
billkey:"Name",
billvalue:"ABC"
},
{
billkey:"Department",
billvalue:"Computer"
},
{
billkey:"Name",
billvalue:"XYZ"
},
{
billkey:"Department",
billvalue:"Electrical"
}];
var arr = [];
var finalObj = [];
for(var i in log){
var someObject = log[i];
for(var j in someObject){
arr.push(someObject[j]);
}
}
for(var k = 0; k < arr.length; k+=4){
finalObj.push({
Name: arr[k+1],
Department: arr[k+3]
});
}
console.log(finalObj);
create the result using forloop
// store the values
var logs=[];
var log=[
{
billkey:"Name",
billvalue:"ABC"
},
{
billkey:"Department",
billvalue:"Computer"
},
{
billkey:"Name",
billvalue:"XYZ"
},
{
billkey:"Department",
billvalue:"Electrical"
},
];
loop the first array
for (i = 0; i < log.length; i++) {
// create empty variable for storing the values
var index = new Array();
// insert the first index value to key
index[log[i].billkey] = log[i].billvalue
// insert the second index value to key
index[log[i+1].billkey] = log[i+1].billvalue
// insert the result in to new array
logs.push(index);
// increment the i with 1
i=i+1;
}
console.log(logs);
You could use Array#reduce and use the remainder operator as witch for using either the last object or create a new one.
var log = [{ billkey: "Name", billvalue: "ABC" }, { billkey: "Department", billvalue: "Computer" }, { billkey: "Name", billvalue: "XYZ" }, { billkey: "Department", billvalue: "Electrical" }],
result = log.reduce(function (r, a, i) {
var o = {};
if (i % 2) {
r[r.length - 1][a.billkey] = a.billvalue;
} else {
o[a.billkey] = a.billvalue;
r.push(o);
};
return r;
}, []);
console.log(result);

Categories