Change array of object to CSV pattern - javascript

i have this following Array :
var objRow = [
{
2011-09-20 : [0, 100, 0],
customerID : C1101,
ANI : 1234
},
{
2011-09-25 : [0, 0, 0],
customerID : C1101,
ANI : 1234
},
{
2011-09-20 : [0, 500, 0],
customerID : C1102,
ANI : 5678
},
{
2011-09-22 : [0, 0, 50],
customerID : C1102,
ANI : 5678
}
]
I want to create CSV Data from array above. But, i have problem to change that array to this CSV pattern :
1234, C1101, 0, 0, 100, 0, 0, 0
5678, C1102, 0, 0, 500, 0, 0, 50
I try to group the customerID using reduce, and because the first index in every object is date. I have some array of dates :
var dateArr = ["2011-09-20", "2011-09-22", "2011-09-25"];
And this is my code :
var result = objRow.reduce(function(prev, curr, index, arr) {
var num = curr["customerID"];
if (!prev[num]) {
prev[num] = [];
}
for (var j = 0; j < dateArr.length; j++) {
prev[num].push(curr[dateArr[j]]);
}
return prev;
}, {});
Update Question
For number combination in date index. I use this rules :
[0, 100, 0] // from first Object
[0, 0, 0] // from second Object
fistObject_firstIndex, secondObject_firstIndex, firstObject_secondIndex, secondObject_secondIndex, firstObject_thirdIndex, secondObject_thirdIndex
0, 0, 100, 0, 0, 0
Up, Down, Up, Down, Up, Down...
How to create CSV Pattern above?
Thank you...

I think this will give you the result you want:
var objRow = [{
date: 2011-09-20,
nums: [0, 100, 0],
customerID: "C1101",
ANI: 1234
}, {
date: 2011-09-25,
nums: [0, 0, 0],
customerID: "C1101",
ANI: 1234
}, {
date: 2011-09-20,
nums: [0, 500, 0],
customerID: "C1102",
ANI: 5678
}, {
date: 2011-09-22,
nums: [0, 0, 50],
customerID: "C1102",
ANI: 5678
}];
//CREATE CSV-FORMATTED STRINGS
var csvLine = "";
var numsArray = new Array();
for (var i=0; i<objRow.length; i++) {
//check if this is the first element with a new 'ANI' (which means a new CSV line starts)
if (objRow[i-1]==(undefined||null) || objRow[i].ANI!=objRow[i-1].ANI) {
//if so, start a new string
csvLine = objRow[i].ANI +", "+ objRow[i].customerID +", "; //add the 'ANI' and 'customerID'
numsArray.length = 0; //clear array
numsArray.push(objRow[i].nums); //store the 'nums' in a separate array
} else {
//if not, add to the existing string
numsArray.push(objRow[i].nums); //store the 'nums' in a separate array
}
//check if this is the last element with the same 'ANI' (which means this CSV line is complete)
if (objRow[i+1]==(undefined||null) || objRow[i].ANI!=objRow[i+1].ANI) {
//add the 'nums' of every object in intertwining order (every 1st, every 2nd, etc.)
for (var k=0; k<numsArray[0].length; k++) {
for (var j=0; j<numsArray.length; j++) {
csvLine += numsArray[j][k].toString() +", ";
}
}
//remove the last comma
if (csvLine.substring(csvLine.length-2) == ", ") {
csvLine = csvLine.substring(0,csvLine.length-2);
}
//output the CSV line
document.getElementById("csv").innerHTML += csvLine + "<br />";
}
}
<div id="csv"></div>
(fiddle: http://jsfiddle.net/5gyp3ce6/16/)
I had to change your array a little bit, because for this to work, the array keys need to all be the same.
Also, I had to change the ID's to strings, otherwise they couldn't be defined.
Instead of writing it to the <div> at the end you can of course add the line to another variable of write it to file or whatever.
If the comments in the code aren't clear enough, just leave a comment and I'll try to explain it better.

Try
var objRow = [
{
"2011-09-20" : [0, 100, 0],
customerID : "C1101",
ANI : 1234
},
{
"2011-09-25" : [0, 0, 0],
customerID : "C1101",
ANI : 1234
},
{
"2011-09-20" : [0, 500, 0],
customerID : "C1102",
ANI : 5678
},
{
"2011-09-22" : [0, 0, 50],
customerID : "C1102",
ANI : 5678
}
];
var arr = [],
res = [],
csv = $.map(objRow, function (v, k) {
// items
arr.push(v.ANI, v.customerID, v[Object.keys(v)[0]]);
// arrays
var a = $.grep(arr, function (val, index) {
return $.isArray(val)
});
// strings
var s = arr.filter(function (i) {
return typeof i === "string"
});
// sort items
res.push([arr.filter(Number)[0]
, s[0]
, a.splice(0, 2).join(",")
, arr.filter(Number).slice(-1)[0]
, s.slice(-1)[0]
, a.join(",")]);
return res
}).slice(-1)[0];
// format text , html
csv = (csv.slice(0, 3) + "<br>" + csv.slice(-3))
.replace(/,/g, ", ");
$("body").append(csv)
var objRow = [
{
"2011-09-20" : [0, 100, 0],
customerID : "C1101",
ANI : 1234
},
{
"2011-09-25" : [0, 0, 0],
customerID : "C1101",
ANI : 1234
},
{
"2011-09-20" : [0, 500, 0],
customerID : "C1102",
ANI : 5678
},
{
"2011-09-22" : [0, 0, 50],
customerID : "C1102",
ANI : 5678
}
];
var arr = [],
res = [],
csv = $.map(objRow, function (v, k) {
arr.push(v.ANI, v.customerID, v[Object.keys(v)[0]]);
// arrays
var a = $.grep(arr, function (val, index) {
return $.isArray(val)
});
// strings
var s = arr.filter(function (i) {
return typeof i === "string"
});
res.push([arr.filter(Number)[0], s[0], a.splice(0, 2).join(","), arr.filter(Number).slice(-1)[0], s.slice(-1)[0], a.join(",")]);
return res
}).slice(-1)[0];
csv = (csv.slice(0, 3) + "<br>" + csv.slice(-3))
.replace(/,/g, ", ");
$("body").append(csv)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

Related

Sort a Json by user.id from a JSON

I have a JSON in which I save the GuildID and then again the UserID
"385524088980111362": {
"672748733737467936": {
"XP": 0,
"Level": 1,
"BisLevel": 100,
"NächsteXP": 0,
"XPIns": 2
},
"866935358448468008": {
"XP": 0,
"Level": 1,
"BisLevel": 100,
"NächsteXP": 0,
"XPIns": 7
}
}
Now I want to sort the users by XPIns from one Guild. I remember this code part here
let obj;
fs.readFile('./xpdata.json', 'utf8', function (err, data) {
if (err) throw err;
obj = JSON.parse(data)
var sorted = Object.entries(obj).sort((a, b) => b[1] - a[1])
});
In the end, the user with more should be in the 1st position (866935358448468008). Can anyone help me?
I've seen a similar question before but couldn't get it to work if there was a GuildID in front of it
The code I had done before (sorry for the sloppy code that was a year ago (Code is updated)):
let obj;
fs.readFile('./userdata.json', 'utf8', function (err, data) {
if (err) throw err;
try {
obj = JSON.parse(data)
} catch (error) {
if(error) return console.log("Ein Fehler ist aufgetreten! " + error);
}
var sorted = Object.entries(obj).sort((a, b) => b[1].Economy.Balance - a[1].Economy.Balance)
if(sorted.length > 10) sorted = sorted.slice(0, 10)
var lBString = "";
var s = 1;
sorted.forEach(user => {
let usertag = Data[user[0]].Tag
lBString += `${s}. ${usertag} • **${user[1].Economy.Balance}$**\n`
s = s += 1
})
let embed = {
title: `Leaderboard Balance`,
description: lBString,
color: 0xFFFF00,
thumbnail: {
url: client.user.avatarURL(),
},
timestamp: new Date(),
footer: {
text: footer,
icon_url: client.user.avatarURL(),
},
}
e.reply({embeds: [embed]});
});
If you simply want the highest ranking user in terms of "XPIns", I suggest you use a Array.reduce() call on the entries of the inner object.
const data = {
"385524088980111362": {
"672748733737467936": {
"XP": 0,
"Level": 1,
"BisLevel": 100,
"NächsteXP": 0,
"XPIns": 2
},
"866935358448468008": {
"XP": 0,
"Level": 1,
"BisLevel": 100,
"NächsteXP": 0,
"XPIns": 7
}
}
};
const topUser = Object.entries(data['385524088980111362']).reduce((acc, cur) => (
acc[1]?.XPIns > cur[1]?.XPIns ? acc : cur
), []);
console.log(topUser);
What I do in cases like this is to use another object as index using a reference of the main array/object
ie:
var index = {};
// replace .id with the attribute you want to use. In your case XPins
index[ object.id ] = main_index_reference;
once you have generated the index, then you can get the keys using Object.keys( index ):
var keys = Object.keys( index );
keys.forEach( function( key ){
var element = main_object[ key ];
// do whatever with the element
} );
Your main_object remains unchanged. In your particular case you want the highest value, all you need to do is to extract the last element from the keys array.
You can try with this. However, the users do not have their ID inside their object, so you'd probably have to patch the ID before sorting.
const data = {
// if the guild could have list of users then it would have been much better
// instead of Object list with ID, Array of objects with ID in it works much faster..
"385524088980111362": {
"672748733737467936": {
// if we had user ID here, then it would have been better
"XP": 0,
"Level": 1,
"BisLevel": 100,
"NächsteXP": 0,
"XPIns": 2
},
"866935358448468008": {
"XP": 0,
"Level": 1,
"BisLevel": 100,
"NächsteXP": 0,
"XPIns": 7
}
}
};
function getSortedUsersByXPins(data, guildId) {
// if guild has array of users, then we won't need Object.values
const sorted = Object.values(data[guildId]).sort((user1, user2) => {
return user2.XPins - user1.XPins
});
return sorted;
}
const sorted = getSortedUsersByXPins(data, '385524088980111362');
console.log(sorted)
You can try it with this solution, in case you want to convert the object to a list. The main issue is the missing identifier if you work with a list.
This assumes that you would use a function like Object.entries before to convert it.
My recommendation: Include the id into the object and convert it to a list.
let guildList = [
{
"XP": 0,
"Level": 1,
"BisLevel": 100,
"NächsteXP": 0,
"XPIns": 2,
"Id": "672748733737467936"
},
{
"XP": 0,
"Level": 1,
"BisLevel": 100,
"NächsteXP": 0,
"XPIns": 7,
"Id": "866935358448468008"
}
];
let aSorted = guildList.sort((a, b) => b.XPIns-a.XPIns)
console.log(aSorted)
Just extract the player objects and sort them, pretty much the way you already described ((p1, p2) => p2.XPIns - p1.XPIns).
Here is an example:
const data = {
"385524088980111362": {
"672748733737467936": {
"XP": 0,
"Level": 1,
"BisLevel": 100,
"NächsteXP": 0,
"XPIns": 2
},
"866935358448468008": {
"XP": 0,
"Level": 1,
"BisLevel": 100,
"NächsteXP": 0,
"XPIns": 7
}
}
}
const res = Object.fromEntries(Object.entries(data).map( ([gid, users]) => [gid, Object.entries(users).map(([id, u]) => ({id, ...u })).sort( (u1, u2) => u2.XPIns - u1.XPIns)] ))
console.log(res)
Note that you cannot create an object with player id as key without losing the order, since JS objects always put numeric keys in ascending order.

Kyu 8 Code Wars - Finding the Sum of an array after removing the highest and lowest values

I am practising on code wars and am currently stuck on a kyu 8 question, all the tests seem to pass bar the last one. I will add my code and the tests below plus the output I get below.
function sumArray(array) {
if (array == null || array.length <= 2) {
return 0
} else {
let largestInt = Math.max.apply(null, array)
let smallestInt = Math.min.apply(null, array)
let indexSmallest = array.indexOf(largestInt)
let indexLargest = array.indexOf(smallestInt)
array.splice(indexSmallest, 1)
array.splice(indexLargest, 1)
let sum = 0
for (let i = 0; i < array.length; i++) {
sum += array[I]
}
return sum
}
}
The tests:
const {
assert
} = require("chai");
it("example tests", () => {
assert.strictEqual(sumArray(null), 0);
assert.strictEqual(sumArray([]), 0);
assert.strictEqual(sumArray([3]), 0);
assert.strictEqual(sumArray([3, 5]), 0);
assert.strictEqual(sumArray([6, 2, 1, 8, 10]), 16);
assert.strictEqual(sumArray([0, 1, 6, 10, 10]), 17);
assert.strictEqual(sumArray([-6, -20, -1, -10, -12]), -28);
assert.strictEqual(sumArray([-6, 20, -1, 10, -13]), 3);
});
The output:
Test Results:
example tests
expected -10 to equal 3
function total(array) {
// always assure at least an empty array.
array = Array.from(array ?? []);
// sort array values ascending.
array.sort((a, b) => a - b);
array.pop(); // remove last/higest value.
array.shift(); // remove first/lowest value.
// for any to be reduced/summed-up (empty) array
// the initial value of zero always assures the
// minimum expected result of zero.
return array
.reduce((total, value) => total + value, 0);
}
const testEntries = [
[ null, 0 ],
[ [ ], 0 ],
[ [ 3 ], 0 ],
[ [ 3, 5 ], 0 ],
[ [ 6, 2, 1, 8, 10 ], 16 ],
[ [ 0, 1, 6, 10, 10 ], 17 ],
[ [ -6, -20, -1, -10, -12 ], -28 ],
[ [ -6, 20, -1, 10, -13 ], 3 ],
];
console.log(
testEntries
.map(([value, result]) =>
`(total([${ value }]) === ${ result }) ... ${ total(value) === result }`
)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

How to get object property list data

I have a list of objects. Every object has a property which is a list of elements:
{ name : 'Club 01'
, id : 1
, form : 45
, points : 0
, tactics : 'neutral'
, played : 0
, gameset : 0
, playedWith : [ 8, 1, 2, 3 ]
}
I want to go through the list and console log all existing elements:
for (let a = 0; a<clubs.width; a++) {
for (let b = 0; b<clubs[a].playedWith.width; b++) {
console.log(clubs[a].playedWith[b]);
}
}
when i do it for one item, this works. however when i do it with a loop as aboce, this brings me to
undefined
Whats wrong with my code? How do i console log all items within playedWith property?
Elikill58 is right. Arrays have length property, not width property.
So your code would work well this way:
for (let a = 0; a < clubs.length; a++){
for (let b = 0; b < clubs[a].playedWith.length; b++){
console.log(clubs[a].playedWith[b]);
}
}
Also, if you want to iterate through all items in the array, just for the sake of simplicity, you can write it like so:
for (const club of clubs) {
for (const width of club.playedWith) {
console.log(width);
}
}
You have to use length instead of width for both loop.
Here is an example :
var clubs = [
{ name : 'Club 01'
, id : 1
, form : 45
, points : 0
, tactics : 'neutral'
, played : 0
, gameset : 0
, playedWith : [ 8, 1, 2, 3 ]
}
];
for (let a = 0; a < clubs.length; a++) {
for (let b = 0; b < clubs[a].playedWith.length; b++) {
console.log(clubs[a].playedWith[b]);
}
}
let b = {
name: 'Club 01',
id: 1,
form: 45,
points: 0,
tactics: 'neutral',
played: 0,
gameset: 0,
playedWith: [8, 1, 2, 3],
move: function() {
return `
${ this.name }and
${this.id }and
${ this.form }and
${ this.points }and
${ this.tactics }and
${ this.played }and
${ this.gameset }and
${ this.playedWith }`
}
};
console.log(b.move())
for (var w in b) {
console.log(${w}:${b.move()})
}
Your best bet is to just do this:
Object.keys(data).forEach((key, i) => {
console.log("Property: " + key, "\nValue: ", data[key])
})
This will give you the property and value. You can also tweak this to have more robust logic for finding or parsing different data types.
You have an array in one of your properties. You can handle it like this.
let clubs = [ {}, {} ]
clubs.forEach((club, i) => {
if (club && Array.isArray(club) || typeof club !== 'object') {
return;
// Stop loop bc club is not an object
}
Object.keys(club).forEach((key, i) => { // Iterate through all the object properties
console.log("Property: " + key, "\nValue: ", club[key])
if (Array.isArray(club[key]) { // Add more conditions or look for certain property names (keys).
console.log('Length of array from property: ', club[key].length)
club[key].map(el => console.log(key + ' value: ' + el))
// You can choose how you want to handle this.
/*
Expected output:
playedWith value: 8
playedWith value: 1
playedWith value: 2
playedWith value: 3
*/
}
})
})
you cant get the array length using width.
try this,
var clubs = [{name: 'Club 01', id:1, form: 45, points: 0, tactics: 'neutral', played: 0, gameset: 0, playedWith: [8,1,2,3]}]
for (let club of clubs) {
for(let playedWothId of club.playedWith){
console.log(playedWothId);
}
}

Convert key, values JSON array to tabular JSON format

I have following JSON data for Chart
var chartJson = [
{
header : '2016',
values : [1, 5, 9]
},
{
header : '2017',
values : [2, 4, 8]
},
{
header : '2018',
values : [3, 1, 5]
}
];
And needs to convert it into this format to feed my HTML table
var tableJson = [
{
2016 : 1,
2017 : 2,
2018 : 3
},
{
2016 : 5,
2017 : 4,
2018 : 1
},
{
2016 : 9,
2017 : 8,
2018 : 5
}
];
Any quick help will be appreciated to convert it into this format.
I tried using this code, but somehow missing on the logic.
let table = [];
for(var row of chartJson ){
for(var value of row.values)
{
table.push(
{
column : row.header,
value : value
});
}
}
var chartJson = [{
header: '2016',
values: [1, 5, 9]
},
{
header: '2017',
values: [2, 4, 8]
},
{
header: '2018',
values: [3, 1, 5]
}
];
let table = [];
chartJson.forEach((row, index) => {
row.values.forEach((val, j) => {
table[j] = { ...table[j],
[row.header]: val
}
});
});
console.log(table)
Iterate through every chartJson's element with its' values(through inner loop) till values' length and make an object from that.
Finally, push that object into the table array.
That's it.
Have a look at the snippet below:
var chartJson = [
{
header: '2016',
values: [1, 5, 9]
},
{
header: '2017',
values: [2, 4, 8]
},
{
header: '2018',
values: [3, 1, 5]
}
];
let table = [];
let len_of_chartJson = chartJson.length, len_of_values = chartJson[0].values.length;
for (var i = 0; i < len_of_chartJson; i++) {
let obj = {};
for (var j = 0; j < len_of_values; j++) {
obj[chartJson[j].header] = chartJson[j].values[i];
}
table.push(obj);
}
console.log(table);
let table = chartJson.reduce((tbl, rec) => {
rec.values.forEach((num, index) => {
if(!tbl[index]){
tbl[index] = {}
}
tbl[index][rec.header] = num
})
return tbl
}, [])
Array reduce function is used to loop through each object, than for each object it loop through each value, checking if the index exist in the table, if it does not exist, it create an empty object at current index. Finally it creates a key value in the current index object.
You read more about reduce function below
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce

Extracting multi-dimentsional arrays in Javascript/JQuery

I'm extracting some data from an SQL source, which I can get into a javascript script as a simple array (shown grouped by dates) which consists of week no, task number and hours spent:
mydata = [
// weekno, taskno, hours
["2014-14",160,37.5],
["2014-15",160,30],
["2014-15",243,7.5],
["2014-16",160,37.5],
["2014-17",0,7.5],
["2014-17",3,7.5],
["2014-17",321,22.5],
["2014-18",0,7.5],
["2014-18",321,30],
["2014-19",3,7.5],
["2014-19",295,30]
];
I'm going to be charting it using HighCharts, and I need to get it into two property arrays like this:
properties = {
categories: [ "2014-14","2014-15","2014-16","2014-17","2014-18","2014-19"],
series: [
// Task Week
// No 14 15 16 17 18 19
//
{ name: '0', data: [ 0, 0, 0, 7.5, 7.5, 0 ] },
{ name: '3', data: [ 0, 0, 0, 7.5, 0, 7.5 ] },
{ name: '160', data: [ 37.5, 30, 37.5, 0, 0, 0 ] },
{ name: '243', data: [ 0, 7.5, 0, 0, 0, 0 ] },
{ name: '295', data: [ 0, 0, 0, 0, 0, 30 ] },
{ name: '321', data: [ 0, 0, 0, 22.5, 30, 0 ] }
]
}
Aside from looping, am I missing some succinct, idiomatic method for doing this?
In case it's of use to anyone, here's a cobbled together solution:
function onlyUnique(value, index, self) {
return self.indexOf(value) === index;
}
var categories = [];
var subcategories = [];
var temp = {};
for (var i = 0; i < myChartData.length; i++) {
key = myChartData[i][0];
taskno = myChartData[i][1];
hours = myChartData[i][2];
if (taskno in temp == false) temp[taskno] = {};
if (key in temp[taskno] == false) temp[taskno][key] = 0;
temp[taskno][key] += hours;
categories.push(myChartData[i][0]);
subcategories.push(myChartData[i][1])
}
var uniqueCategories = categories.filter(onlyUnique).sort();
var uniqueSubcategories = subcategories.filter(onlyUnique).sort(function(a, b) {
return a - b
});
var series = [];
for (var i = 0; i < uniqueSubcategories.length; i++) {
subcatKey = uniqueSubcategories[i];
series[i] = { name: 'Task ' + subcatKey, data: [] };
for (var j = 0; j < uniqueCategories.length; j++) {
catKey = uniqueCategories[j];
series[i]['data'].push(temp[subcatKey][catKey] ? temp[subcatKey][catKey] : 0);
}
}
where series and uniqueCategories are the required data.

Categories