Fill in missing data in Javascript - javascript

I have an array of objects like this:
[
{
"time": 1,
"value": 405.56
},
{
"time": 2,
"value": 407.64
},
{
"time": 4,
"value": 403.26
},
{
"time": 5,
"value": 403.26
}
]
However, there are no objects at some time (eg 3 is missing in the above example).
For setting the value of this missing data to a default value, I found this thread. However, what I want to do is back-fill the data. For example, I want to create a 3 object so it has the value of the previous object (407.64).
Is there a Javascript library available for doing this kind of manipulation? I do not want to code it myself as far as possible.
EDIT: There might be more missing values but the identifiers (time) will always be numeric.

WORKING FIDDLE
var test = [
{
"time": 1,
"value": 405.56
},
{
"time": 2,
"value": 407.64
},
{
"time": 7,
"value": 403.26
},
{
"time": 12,
"value": 403.26
}
]
function fill() {
var tmp = [];
for (var i = 0, len = test.length - 1; i < len; i++) {
if (test[i]["time"] == test[i+1]["time"] - 1) {
tmp.push(test[i]);
} else {
for (var j = test[i]["time"], l = test[i+1]["time"]; j < l; j++) {
tmp.push(test[i]);
};
}
};
return tmp;
};
function printArray(arr) {
for (var i = 0, len = arr.length; i < len; i++) {
document.body.innerHTML += "<p>" + i + ": " + JSON.stringify(arr[i]) + "</p>";
}
};
printArray(fill(test));

If you want with javascript code then try this-
function fillArray(arr){
var i=1;
while(i<arr.length){
if((arr[i]["time"]*1-arr[i-1]["time"]*1) > 1){
arr.splice(i,0,{"time":i+1, "value": arr[i-1]["value"]});
}
i++;
}
//console.log(arr);
return arr;
}

Related

Comparing information from an API call and an Array

I'm trying to compare the results of an API call to an existing array. Basically, I want to make a function that will loop through the array, then loop through the data from the API to see if there's a match.
Here's an example of the array I'm working with
let array = [ {
"name": "student1",
"id": 134},
{
"name": "student2",
"id": 135},
{
"name": "student3",
"id": 136}
]
Here's my function in JavaScript/jQuery
function getData() {
$.ajax({
url: "www.studentapi.com",
dataType: "json"
}).done(function(data) {
console.log(data)
}
}
The data I get back looks kind of like this:
[ {
"id": 134,
"score": 45},
{
"id": 138,
"score": 67},
{
"id": 139,
"score": 34}
]
I'm trying to find a way to find the matching ids in the array and in the data. So far I've tried:
for (let j =0; j < data.length; j++) {
if (array[j]["id"] === data[j].id) {
console.log("we have a match!")
}
else {
console.log("not a match!");
}
}
But this isn't working. Am I doing something incorrectly over here?
You can use find on an array to find an element that matches some conditional.
The below logic also uses arrow functions, but could be changed to use normal function(){}
let array = [
{
"name": "student1",
"id": 134
},
{
"name": "student2",
"id": 135
},
{
"name": "student3",
"id": 136
}
];
let data = [
{
"id": 134,
"score": 45
},
{
"id": 138,
"score": 67
},
{
"id": 139,
"score": 34
}
];
let studentData = array.map(student=>{
student.data = data.find(record=>record.id === student.id) || {};
return student;
});
console.log(studentData);
I would use the javascript filter function.
let matchingStudents = array.filter(student => {
return data.find(jsonData => student.id === jsonData.id);
});
There matchingStudents would hold all students present in the first array that are present in the second.
If you are wondering about the syntax, this is ES6. Next generation javascript. To write it in old javascript it'd be:
var matchingStudents = array.filter(function(student){
return data.find(function(jsonData){ return student.id === jsonData.id});
}
To specifically answer your question Am I doing something incorrectly over here?
Your search code here assumes that array and data will contain the exact same ids in the exact same order:
for (let j =0; j < data.length; j++) {
if (array[j]["id"] === data[j].id) {
Based on the sample data you provided, this isn't the case; you can't always compare array[j] to data[j] to match ids because (for example) it's possible you need to match array[4] to data[6].
One solution to this problem is to use a nested loop:
for (let i = 0; i < array.length; i++) {
for (let j = 0; j < data.length; j++) {
if (array[i].id === data[j].id) {
This way you'll compare every entry in array to every entry in data when looking for matches. (This is similar to what the solutions suggesting array.map and data.find are doing, with some smart early-out behavior.)
Another approach would be to sort both lists and step forward through them together.
let array = [
{ "id": 134, "name": "student1" },
{ "id": 139, "name": "student2" },
{ "id": 136, "name": "student3" }
];
let data = [
{ "id": 134, "score": 45 },
{ "id": 138, "score": 67 },
{ "id": 139, "score": 34 }
];
array.sort((a, b) => a.id - b.id)
data.sort((a, b) => a.id - b.id)
let data_i = 0;
for (let array_i = 0; array_i < array.length; array_i++) {
while (data[data_i].id < array[array_i].id) {
data_i++;
}
if (data_i < data.length && data[data_i].id === array[array_i].id) {
console.log(`Matched ${array[array_i].name} to score ${data[data_i].score}`);
} else {
console.log(`No match found for ${array[array_i].name}`);
}
}

How does `lookupIndex[row[lookupKey]] = row;` work?

I am reading learnjsdata.com and came across this unfamiliar JavaScript syntax. The syntax is as follows:
lookupIndex[row[lookupKey]] = row;
Anyone know what's happening here? I haven't seen syntax like this. Used in context:
Data
var articles = [{
"id": 1,
"name": "vacuum cleaner",
"weight": 9.9,
"price": 89.9,
"brand_id": 2
}, {
"id": 2,
"name": "washing machine",
"weight": 540,
"price": 230,
"brand_id": 1
}, {
"id": 3,
"name": "hair dryer",
"weight": 1.2,
"price": 24.99,
"brand_id": 2
}, {
"id": 4,
"name": "super fast laptop",
"weight": 400,
"price": 899.9,
"brand_id": 3
}];
var brands = [{
"id": 1,
"name": "SuperKitchen"
}, {
"id": 2,
"name": "HomeSweetHome"
}];
Function & Invocation
function join(lookupTable, mainTable, lookupKey, mainKey, select) {
var l = lookupTable.length,
m = mainTable.length,
lookupIndex = [],
output = [];
for (var i = 0; i < l; i++) { // loop through l items
var row = lookupTable[i];
lookupIndex[row[lookupKey]] = row; // create an index for lookup table
}
for (var j = 0; j < m; j++) { // loop through m items
var y = mainTable[j];
var x = lookupIndex[y[mainKey]]; // get corresponding row from lookupTable
output.push(select(y, x)); // select only the columns you need
}
return output;
};
var result = join(brands, articles, "id", "brand_id", function(article, brand) {
return {
id: article.id,
name: article.name,
weight: article.weight,
price: article.price,
brand: (brand !== undefined) ? brand.name : null
};
});
console.log(result);
Appreciate any answers or pointers, thanks!
Think of it as two separate function calls:
var rowLookup = row[lookupKey];
lookupIndex[rowLookup] = row;
It's the same as doing it all in the same line:
lookupIndex[row[lookupKey]] = row;

complicated custom filter for nested ng-repeat

I've stuck for this for 2 days, tried so many ways still couldn't get it right. I can't change the API data so I have to deal with front end handling. I really need some help.
$scope.stationary = [{
"name": "Pen",
"data": [{
"date": "1-10-2017",
"inventory": 25
}, {
"date": "2-10-2017",
"inventory": 21
}]
}, {
"name": "Color Pencil",
"data": [{
"date": "1-10-2017",
"inventory": 3
}, {
"date": "2-10-2017",
"inventory": 0
}]
}, {
"name": "Color Pencil Special",
"data": [{
"date": "1-10-2017",
"inventory": 2
}, {
"date": "2-10-2017",
"inventory": 1 // make this view to '-' since inventory of color pencil is zero
}]
}]
http://jsfiddle.net/op2zd2vr/
The case is if color pencil's inventory is zero, should display '-' on color pencil special column.
Try this:
Updated Answer:
myApp.filter('customFilter', function() {
return function(items) {
for (var i = 0; i < items.length; i++) {
for (var k = 0; k < items[i].data.length; k++) {
if (i != 0 && items[i - 1].data[k].inventory == 0) {
items[i].data[k]['isZero'] = true;
} else {
items[i].data[k]['isZero'] = false;
}
}
}
return items;
};
});
See Updated jsfiddle link.
It's working for me.
Guess you have to manipulate the datas itselves, you cannot simply use a filter for this particular case.
Here's my fiddle: http://jsfiddle.net/op2zd2vr/2/
Solution used (depending ont the datas' names):
var positions = [];
$scope.stationary.forEach(function (s) {
if(s.name === 'Color Pencil'){
for(var i = 0; i < s.data.length; i++){
if(s.data[i].inventory === 0){
positions.push(i);
}
}
}
if(s.name === 'Color Pencil Special'){
for(var i = 0; i < s.data.length; i++){
if(positions.indexOf(i) >= 0){
s.data[i].inventory = '-';
}
}
}
});

Push Unique Objects to JavaScript Array

How do I push an object into an specified array that only updates that array? My code pushes an object and updates all arrays, not just the specified one.
Here is the structure of the data:
{
"d": {
"results": [
{
"Id": 1,
"cost": "3",
"item": "Project 1",
"fiscalyear": "2014",
"reportmonth": "July"
}
]
}
}
Here is a sample of the desired, wanted results:
{
"Project 1": [
{
"date": "31-Jul-14",
"rating": "3"
},
{
"date": "31-Aug-14",
"rating": "4"
}
],
"Project 2": [
{
"date": "31-Jul-14",
"rating": "2"
}
]
}
This is my attempt:
var results = data.d.results;
var date;
var projectObj = {},
projectValues = {},
project = '';
var cost = '',
costStatus = '';
for (var i = 0, m = results.length; i < m; ++i) {
project = results[i]['item'];
if (!projectObj.hasOwnProperty(project)) {
projectObj[project] = [];
}
// use Moment to get and format date
date = moment(new Date(results[i]['reportmonth'] + ' 1,' + results[i]['fiscalyear'])).endOf('month').format('DD-MMM-YYYY');
// get cost for each unique project
costStatus = results[i]['cost'];
if (costStatus == null || costStatus == 'N/A') {
cost = 'N/A';
}
else {
cost = costStatus;
}
projectValues['rating'] = cost;
projectValues['date'] = date;
projectObj[project].push(projectValues);
}
Here is a Fiddle with the undesired, unwanted results:
https://jsfiddle.net/yh2134jn/4/
What am I doing wrong?
That is because You do not empty it new iteration. Try this:
for (var i = 0, m = results.length; i < m; ++i) {
projectValues = {};
project = results[i]['item'];
....
}

JavaScript compare two arrays(key/value pairs) and copy value from one to the other if key matches

I have two arrays containing key/value pairs.
{
"containerOne": [{
"Id": 1,
"Title": "TitleOne",
"Responsibility": "ValueOne"
}, {
"Id": 2,
"Title": "TitleTwo",
"Responsibility": "ValueTwo"
}]
}
{
"containerTwo": [{
"Id": 1,
"Title": "TitleOne",
"Responsibility": null
}, {
"Id": 2,
"Title": "TitleTwo",
"Responsibility": "null
}
]
}
I'd like to compare both arrays and compare the title of each container. If the titles match, then I'd like to copy the Responsibility value from containerOne to containerTwo. The ID's will not match, so that can be ruled out. Only the titles will be consistent.
What is the most efficient way to do this please?]
Thanks
=====================================================================
EDIT
=====================================================================
Looking at the arrays a little closer, there is a subtle difference in the data being returned:
{
"AMLookupTasksList":
[
{
"Id":1,
"Title":"Create and Maintain an Onboarding Document",
"Responsibility":"1. Onboarding|f101ccf1-c7d5-42e7-ba8f-48e88ac90a3d"
},
{
"Id":2,
"Title":"Execute Onboarding for New Consultants",
"Responsibility":"1. Onboarding|f101ccf1-c7d5-42e7-ba8f-48e88ac90a3d"
}
]
}
{
"AMTasksList":
[
{
"Id":4,
"Title":
{
"$M_1":13,"$c_1":"Create and Maintain an Onboarding Document"
},
"Responsibility":null
},
{
"Id":17,
"Title":
{
"$M_1":12,"$c_1":"Execute Onboarding for New Consultants"
},
"Responsibility":null
}
]
}
Do I have additional looping to get to the Title value in the second array?
This might be a bit of overkill but it ignores the sequence and does a look up in each object.
I had to fix some syntax in your objects but I include that: named the objects and took a quote off one of the null values.
var obj1 = {
"containerOne": [{
"Id": 1,
"Title": "TitleOne",
"Responsibility": "ValueOne"
}, {
"Id": 2,
"Title": "TitleTwo",
"Responsibility": "ValueTwo"
}]
};
var obj2 = {
"containerTwo": [{
"Id": 1,
"Title": "TitleOne",
"Responsibility": null
}, {
"Id": 2,
"Title": "TitleTwo",
"Responsibility": null
}]
};
Now the code:
// lookup for first object:
var lookup = {};
// create referece to list above and use it everywhere
lookup.list = obj1;
for (var i = 0, len = lookup.list.containerOne.length; i < len; i++) {
lookup[lookup.list.containerOne[i].Title] = lookup.list.containerOne[i];
}
// lookup for second object
var otherLookup = {};
otherLookup.list = obj2;
for (var i = 0, len = otherLookup.list.containerTwo.length; i < len; i++) {
otherLookup[otherLookup.list.containerTwo[i].Title] = otherLookup.list.containerTwo[i];
}
// copy value for Responsibility from first to second on each matched in second.
var i = 0;
var len = lookup.list.containerOne.length;
for (i; i < len; i++) {
// looks up value from second list in the first one and if found, copies
if (lookup[otherLookup.list.containerTwo[i].Title]) {
otherLookup.list.containerTwo[i].Responsibility = lookup[otherLookup.list.containerTwo[i].Title].Responsibility;
}
}
// alerts new value using lookup
alert(otherLookup["TitleOne"].Responsibility);
EDIT for new structure, but same answer really:
var obj1 = {
"AMLookupTasksList": [{
"Id": 1,
"Title": "Create and Maintain an Onboarding Document",
"Responsibility": "1. Onboarding|f101ccf1-c7d5-42e7-ba8f-48e88ac90a3d"
}, {
"Id": 2,
"Title": "Execute Onboarding for New Consultants",
"Responsibility": "1. Onboarding|f101ccf1-c7d5-42e7-ba8f-48e88ac90a3d"
}]
};
var obj2 = {
"AMTasksList": [{
"Id": 4,
"Title": {
"$M_1": 13,
"$c_1": "Create and Maintain an Onboarding Document"
},
"Responsibility": null
}, {
"Id": 17,
"Title": {
"$M_1": 12,
"$c_1": "Execute Onboarding for New Consultants"
},
"Responsibility": null
}]
};
var lookup = {};
// create refernece to list above and use it everywhere
lookup.list = obj1;
for (var i = 0, len = lookup.list.AMLookupTasksList.length; i < len; i++) {
lookup[lookup.list.AMLookupTasksList[i].Title] = lookup.list.AMLookupTasksList[i];
}
var otherLookup = {};
otherLookup.list = obj2;
for (var i = 0, len = otherLookup.list.AMTasksList.length; i < len; i++) {
otherLookup[otherLookup.list.AMTasksList[i].Title.$c_1] = otherLookup.list.AMTasksList[i];
}
// copy value for Responsibility from first to second
var i = 0;
var len = otherLookup.list.AMTasksList.length;
for (i; i < len; i++) {
if (lookup[otherLookup.list.AMTasksList[i].Title.$c_1]) {
otherLookup.list.AMTasksList[i].Responsibility = lookup[otherLookup.list.AMTasksList[i].Title.$c_1].Responsibility;
}
}
alert(otherLookup["Create and Maintain an Onboarding Document"].Responsibility);
Fiddle for second answer: http://jsfiddle.net/n22V8/
First, create a dictionary from containerTwo:
var c2dict = {};
var c2i = containerTwo.innerContainer;
for (var i = 0; i < c2i.length; i++) {
c2dict[c2i[i].Title] = c2i[i];
}
Now use this to do the copying of propertyies when titles match:
var c1i = containerOne.innerContainer;
for (var i = 0; i < c1i.length; i++) {
if (c2dict[c1i[i].Title]) {
c2dict[c1i[i].Title].Property = c1i[i].Property;
}
}
You should compare properties and set them as the following:
containerOne.innerContainer.forEach(function (element,index) {
containerTwo.innerContainer.forEach(function (element2,index2) {
if (element.Title === element2.Title && element.Property != element2.Property) {
element2.Property = element.Property;
}
});
});

Categories