Create Table Based on Changing JSON Output - javascript

So to GET an output like this, I had to use some pretty cool tricks (see Analyzing Data from JSON in JavaScript). Please note my data in this example (# rows) is different.
var feeds = [].concat.apply([], dataSet_parsed.map(s => s.data));
//flattens arrays AGAIN to show all targets
var targets = [].concat.apply([], feeds.map(s => s.data));
//return target hits total
var targetList = targets.reduce(
function(prev, cur) {
var val = cur["val"];
prev[val] = ((prev[val] || 0) + 1);
return prev;
}, {});
// Output: {TargetA: 5, TargetB: 6, TargetC: 4, TargetD: 2}
Basically, I'm trying to get a count of how many times a target was seen per group. And fantastic! this works.
Here's my question. how do I display the output---
{TargetA: 5, TargetB: 6, TargetC: 4, TargetD: 2}
---in a table? There are no guarantees that I will always return the same TYPE of Targets (i.e. next load I could have:
{TargetK: 10, TargetL: 2, TargetM: 5, TargetN: 3, TargetO: 7, TargetP: 8}
I've tried using JSON.stringify and .replace() but I'm not getting very far. And even after that, I don't think I could style that output very well.
JSON.stringify(targetList).replace(/\}/g,'').replace(/\{/g,'')

Related

JS looping trough fetch in API

Ok, so recently I've been working on this code, and I was so puzzled and frustrated why it is ordering the output randomly. But then later I realized that it is loading which ever channel loads fastest, then it's index becomes 0, which ever loads the fastest next, becomes 1, whichever loads fastest next becomes 2, etc.
var channels = [
"UCIgnIPif1LQxkdbvBmGNNuA", // channel 1
"UC_Qs0JhHoysG4LItMgGMHHQ", // channel 2
"UC_puGdwVL1kc5VRhaZc6Arw", // channel 3
"UCQvwHZVCrljzvaLVX33Qaaw" // channel 4
];
var key = "cant share but i will tell you the output of the code"
var subCounts = [];
function getSubs(id, key){
for(var i = 0; i < channels.length; i++){
fetch('https://www.googleapis.com/youtube/v3/channels?part=statistics&id='+channels[i]+'&key='+key+'')
.then(response => {
return response.json()
}).then(data => {
//name[i].innerHTML =
subCounts.push(data['items'][0].statistics.subscriberCount);
});
} // for loop close
}
setTimeout(function(){
console.log(subCounts);
// output example: 4, 5, 6, 7
// another output: 5, 7, 6, 4
// another output: 7, 4, 5, 6
}, 1500) // good enough for the fetch to load
it's just random (which ever loads first comes first).
What I want it to do though:
I want it to load based on the order of the channels. So channel 1 needs to load first, then channel 2, then channel 3, etc. Instead of which ever loads first.
Any help, suggestions, tips would be appriciated.
Thank You.
Assuming that it is OK for you to wait for all requests to complete before you begin handling their responses, then Promise.all should allow you to accomplish your goal. Below is your code rewritten roughly to use Promise.all:
var channels = [
"UCIgnIPif1LQxkdbvBmGNNuA", // channel 1
"UC_Qs0JhHoysG4LItMgGMHHQ", // channel 2
"UC_puGdwVL1kc5VRhaZc6Arw", // channel 3
"UCQvwHZVCrljzvaLVX33Qaaw" // channel 4
];
var key = "cant share but i will tell you the output of the code"
var subCounts = [];
function getSubs(id, key) {
var requests = [];
var currentRequest;
for (var i = 0; i < channels.length; i++) {
currentRequest = fetch('https://www.googleapis.com/youtube/v3/channels?part=statistics&id=' + channels[i] + '&key=' + key + '');
requests.push(currentRequest);
} // for loop close
Promise.all(requests).then((responses) => {
for (let j = 0; j < responses.length; j++) {
const currentResponse = responses[j];
const data = currentRequest.json();
subCounts.push(data['items'][0].statistics.subscriberCount);
}
});
}
setTimeout(function () {
console.log(subCounts);
// output example: 4, 5, 6, 7
// another output: 5, 7, 6, 4
// another output: 7, 4, 5, 6
}, 1500) // good enough for the fetch to load
Please note that I generally opted to use modern variable declarations of let/const-- you won't generally want to mix the older var into code using let/const so it would be best to update all of it, or, less desirable, use var for all declarations. Also, this isn't tested (obviously), so it will likely need some rework for your purposes.
If every millisecond counts and you needed to process them in order but as soon as they came in, this would need to be written differently. If you reply as such I can try to put together a POC.
This would be a good use for Promise.all (docs)
Something like:
Promise.all(
channels.map(
channel => fetch('https://www.googleapis.com/youtube/v3/channels?part=statistics&id='+channel+'&key='+key+'')
)
)
.then(Promise.all((responses) => responses.map(response => response.json()))
.then(responses => {
// now responses is an array in order of the results that you can process as you wish
});
An alterantive would be to make subCounts be of the same length as channels, and place the ith channel result at index i in the subCounts array.
You can use async await,
var data = await fetch('https://www.googleapis.com/youtube/v3/channels?part=statistics&id='+channels[i]+'&key='+key+'')
.then(response => {
return response.json()
}).then(data => {
//name[i].innerHTML =
});
subCounts.push(data['items'][0].statistics.subscriberCount);

More sophisticated way to split column from array

I have an array in the following format:
let initialDataset=
[
[3.6216,8.6661,-2.8073,-0.44699,1 ],
[4.5459,8.1674,-2.4586,-1.4621,0 ],
[3.866,-2.6383,1.9242,0.10645,1 ],
[3.4566,9.5228,-4.0112,-3.5944,0 ],
[0.32924,-4.4552,4.5718,-0.9888,0 ],
//and so on...
Goal: Seperate last column/element from each array inside 'initialDataset' variable and put them into a distinct array. They have to be in the same index too. Such as:
let initialDataset=
[
[3.6216,8.6661,-2.8073,-0.44699],
[4.5459,8.1674,-2.4586,-1.4621],
[3.866,-2.6383,1.9242,0.10645],
[3.4566,9.5228,-4.0112,-3.5944],
[0.32924,-4.4552,4.5718,-0.9888],
let division=[1,0,1,0,0];
To accomplish this, i used following piece of code:
let division=[];
for(i=0;i<initialDataset.length;i++){
division[i]=initialDataset[i].pop();
}
It gets the work done but i didn't quite like it. Looking for a better way to achieve it. Any suggestions in terms of optimization and code quality wise ? Thanks in advance.
You could map the popped value.
var data = [[3.6216, 8.6661, -2.8073, -0.44699, 1], [4.5459, 8.1674, -2.4586, -1.4621, 0], [3.866, -2.6383, 1.9242, 0.10645, 1], [3.4566, 9.5228, -4.0112, -3.5944, 0], [0.32924, -4.4552, 4.5718, -0.9888, 0]],
division = data.map(a => a.pop());
console.log(division);
Functional answer using a handy, reusable last function. This method does not mutate the input array.
const data = [[3.6216,8.6661,-2.8073,-0.44699,1],[4.5459,8.1674,-2.4586,-1.4621,0],[3.866,-2.6383,1.9242,0.10645,1],[3.4566,9.5228,-4.0112,-3.5944,0],[0.32924,-4.4552,4.5718,-0.9888,0]]
const last = array => {
const { length } = array
return length > 0 ? array[length - 1] : undefined
}
const division = data.map(last)
console.log(division)

Creating a new array with elements from input array

I have an array like below
[{
"IM_Id":1,
"IM_Name":"Hello",
"ItemNumber":2001,
"FE_Id":2,
"FE_Name":"Wall",
"FE_Code":"XYZ",
"FC_Id":[2,3],
"FC_Name":["ABC","PQR"],
"FC_Value":[9,7],
"OC_Id":6,
"OC_Name":"Rai",
"OC_Price":"$30",
"CH_Id":4,
"CH_Name":"Sen",
"CH_Code":"LMN",
"CO_Id":[5,9],
"CO_Name":["xyz","pqr"],
"CO_Value":["qqq","LMN"]
},
{
"IM_Id":2,
"IM_Name":"World",
"ItemNumber":2002,
"FE_Id":3,
"FE_Name":"WallMart",
"FE_Code":"009F",
"FC_Id":[4,5],
"FC_Name":["ABCD","PQRS"],
"FC_Value":[4,2],
"OC_Id":7,
"OC_Name":"Raj",
"OC_Price":"$60",
"CH_Id":7,
"CH_Name":"Ken",
"CH_Code":"IJK"
}]
You can see FC_Id,FC_Name,FC_Value have 2 elements and these 3 parameters are actually related.
Similarly all parameters prepended with CO have same pattern.
I want my resulting array should consider every element of array one by one.
So for the first element of array, it should consider one by one elements of FC_Id,FC_Name,FC_Value,CO_Id,CO_Name and CO_Value.
It should actually consider all the elements of subarrays and main array both.
And hence my result should be something as below
[{
"IM_Id":1,
"IM_Name":"Hello",
"ItemNumber":2001,
"FE_Id":2,
"FE_Name":"Wall",
"FE_Code":"XYZ",
"FC_Id":2, //Here it took the first element
"FC_Name":"ABC", // //Here it took the first element
"FC_Value":9, ////Here it took the first element
"OC_Id":6,
"OC_Name":"Rai",
"OC_Price":"$30",
"CH_Id":4,
"CH_Name":"Sen",
"CH_Code":"LMN",
"CO_Id":5,
"CO_Name":"xyz",
"CO_Value":"qqq"
},
{
"IM_Id":1,
"IM_Name":"Hello",
"ItemNumber":2001,
"FE_Id":2,
"FE_Name":"Wall",
"FE_Code":"XYZ",
"FC_Id":3, //Here it took the second element
"FC_Name":"PQR", //Here it took the second element
"FC_Value":7,//Here it took the second element
"OC_Id":6,
"OC_Name":"Rai",
"OC_Price":"$30",
"CH_Id":4,
"CH_Name":"Sen",
"CH_Code":"LMN",
"CO_Id":9,
"CO_Name":"pqr",
"CO_Value":"LMN"
},
{
"IM_Id":2,
"IM_Name":"World",
"ItemNumber":2002,
"FE_Id":3,
"FE_Name":"WallMart",
"FE_Code":"009F",
"FC_Id":4,
"FC_Name":"ABCD",
"FC_Value":4,
"OC_Id":7,
"OC_Name":"Raj",
"OC_Price":"$60",
"CH_Id":7,
"CH_Name":"Ken",
"CH_Code":"IJK",
"CO_Id":"-",
"CO_Name":"-",
"CO_Value":"-"
},
{
"IM_Id":2,
"IM_Name":"World",
"ItemNumber":2002,
"FE_Id":3,
"FE_Name":"WallMart",
"FE_Code":"009F",
"FC_Id":5,
"FC_Name":"PQRS",
"FC_Value":2,
"OC_Id":7,
"OC_Name":"Raj",
"OC_Price":"$60",
"CH_Id":7,
"CH_Name":"Ken",
"CH_Code":"IJK",
"CO_Id":"-", // as there's no element here we are inputting a '-'
"CO_Name":"-",
"CO_Value":"-"
}
]
Also, note that as there are no CO_ values for Item Number 2002 am putting a "-".
There will be more more other parameters in the array too I need some dynamic logic to create the resulting array
Something like this:
For each element of the data
Find at least one list of IDs between FC and CO (or construct a one-element list if no such list is found)
Iterate its length, and replace the relevant entries with subentries
Flatten the result
let data = [{"IM_Id":1,"IM_Name":"Hello","ItemNumber":2001,"FE_Id":2,"FE_Name":"Wall","FE_Code":"XYZ","FC_Id":[2,3],"FC_Name":["ABC","PQR"],"FC_Value":[9,7],"OC_Id":6,"OC_Name":"Rai","OC_Price":"$30","CH_Id":4,"CH_Name":"Sen","CH_Code":"LMN","CO_Id":[5,9],"CO_Name":["xyz","pqr"],"CO_Value":["qqq","LMN"]},{"IM_Id":2,"IM_Name":"World","ItemNumber":2002,"FE_Id":3,"FE_Name":"WallMart","FE_Code":"009F","FC_Id":[4,5],"FC_Name":["ABCD","PQRS"],"FC_Value":[4,2],"OC_Id":7,"OC_Name":"Raj","OC_Price":"$60","CH_Id":7,"CH_Name":"Ken","CH_Code":"IJK"}];
let result = [].concat(...data.map(r =>
(Array.isArray(r.FC_Id) ? r.FC_Id :
Array.isArray(r.CO_Id) ? r.CO_Id :
[0]
).map((_, i) =>
Object.assign({}, r, {
FC_Id: r.FC_Id ? r.FC_Id[i] : "-",
FC_Name: r.FC_Name ? r.FC_Name[i] : "-",
FC_Value: r.FC_Value ? r.FC_Value[i] : "-",
CO_Id: r.CO_Id ? r.CO_Id[i] : "-",
CO_Name: r.CO_Name ? r.CO_Name[i] : "-",
CO_Value: r.CO_Value ? r.CO_Value[i] : "-",
})
)
));
console.log(result);
Here is a snippet to achieve this. If you need to handle more properties with values as arrays, simple add them to props array :
let props = ["FC_Id", "FC_Name", "FC_Value", "CO_Id", "CO_Name", "CO_Value"]
Sample snippet
let arr = [{
"IM_Id": 1,
"IM_Name": "Hello",
"ItemNumber": 2001,
"FE_Id": 2,
"FE_Name": "Wall",
"FE_Code": "XYZ",
"FC_Id": [2, 3],
"FC_Name": ["ABC", "PQR"],
"FC_Value": [9, 7],
"OC_Id": 6,
"OC_Name": "Rai",
"OC_Price": "$30",
"CH_Id": 4,
"CH_Name": "Sen",
"CH_Code": "LMN",
"CO_Id": [5, 9],
"CO_Name": ["xyz", "pqr"],
"CO_Value": ["qqq", "LMN"]
},
{
"IM_Id": 2,
"IM_Name": "World",
"ItemNumber": 2002,
"FE_Id": 3,
"FE_Name": "WallMart",
"FE_Code": "009F",
"FC_Id": [4, 5],
"FC_Name": ["ABCD", "PQRS"],
"FC_Value": [4, 2],
"OC_Id": 7,
"OC_Name": "Raj",
"OC_Price": "$60",
"CH_Id": 7,
"CH_Name": "Ken",
"CH_Code": "IJK"
}
]
function convertArray() {
let result = [];
let props = ["FC_Id", "FC_Name", "FC_Value", "CO_Id", "CO_Name", "CO_Value"]
arr.forEach(function(obj) {
// Assume `FC_Id` array length is the reference array length
obj["FC_Id"].forEach(function(id, $index) {
// Create a clone of original object, so that we only have to override `props` defined above
let objClone = JSON.parse(JSON.stringify(obj));
// Override each prop value
props.forEach(function(prop) {
// Ensure original object property is an array with enough elements
if (obj[prop] instanceof Array && obj[prop].length > $index) {
objClone[prop] = obj[prop][$index];
}
else {
// else simply use an hyphen as value
objClone[prop] = "-";
}
});
// Push clone to result
result.push(objClone);
});
});
return result;
}
let newArray = convertArray();
console.log(JSON.stringify(newArray, null, 2));
From where are you creating this array . If you create this array in JavaScript or from webservice class. Then we could tell you the generic class for it. And a small method to convert the class element in your desire output array.
Let me answer in JavaScript code.
// I am creating a array object manual you could get it from source or from server json.
var Arr=[];
var obj={};
Obj.Name="fc_name";
obj.Value="12";
Arr.push(obj);
var obj={};
Obj.Name="fc_value";
obj.Value="dieje";
Arr.push(obj);
Similarly push all the elements in the array.
Then you will have a array of object with name value.
Arr=[
{"Name":"fc_value",
"Value":""dieje"
},
...
});
Now use below function to convert this array of object into your desire array.
function Convert(arr)
{
var array=[];
var obj={};
Arr.forEach(value)
{
obj[value.Name]=value.Value;
}
array.push(obj);//this is for single object you could apply loop to get the multiple value in array.
}

update object one by one of asyn

For my app, there are matches and schedules. My idea is simple, but i cannot find a way to do it with angularjs for its asyn nature.
for matches, there are so called [a, b, c] three matches as an example.
for schedules, there are more than three resources such as [1, 2, 4, 5, 6, 7].
I would like to pair matches with available schedules so that [a1, b2, c4] with unique pairing.
I just wonder why the follow code doesn't work:
for (var u in matches){
var matchDefer = $q.defer();
var matchPromise = matchDefer.promise;
var match = matches[u]
var schedule = schedules[u];
Matches.get({matchId: match._id}, function(matchResponse){
console.info('schedule', schedule);
matchResponse.AddSchedule(schedule, matchDefer);
});
matchPromise.then(function(result){
console.info('result', result);
}, function(reason){
console.info('reason', reason);
});
}
And the following code is in the match service:
Matches.prototype.AddSchedule = function(schedule, defer) {
this.schedule = schedule._id;
this.$update(function(matchResponse){
schedule.match = matchResponse._id;
schedule.$update(function(scheduleResponse){
defer.resolve(scheduleResponse._id);
});
});
Could anyone help me even just give me some hints to do it, thanks!

unique values in array count

I have an array like the following
var data = [
["1"," 101_30.1.101_34","0.0200112629","mm/s","[OK]"],
["1"," 101_30.1.101_35","0.0146548533","mm/s","[OK]"],
["1"," 101_30.1.101_45","0.0146548533","mm/s","[OK]"],
["1"," 101_42.2.101_43","0.0101406257","mm/s","[OK]"],
["2"," 102_17.3.102_38","5.1719756","mm/s","[WA]"],
["2"," 102_17.3.102_39","3.5886707","mm/s","[WA]"],
["2"," 102_17.3.102_44","9.4615074E-4","mm/s","[OK]"],
["2"," 102_40.4.102_41","4.8159785","mm/s","[OK]"],
["3"," 204_15","3.8374166","mA","[OK]"],
["4"," 501_11","1027.5156","RPM","[WA]"]
]
What im trying to do is find how many unique array there are. Example 1=4,2=4,3=1,4=1
The data is coming from a database, so the number of arrays can always change.
Here is a simple jsfiddle of what im talking about JsFiddle
Try something like this:
var count = {};
$.each(data, function(){
var num = this[0]; // Get number
count[num] = count[num]+1 || 1; // Increment counter for each value
});
console.log(count); // {1: 4, 2: 4, 3: 1, 4: 1}

Categories