Reduce function doesn't seem to work properly - javascript

I'm using the function below to extract and create issue objects form all documents of type inspection:
function (doc) {
if(doc.doctype === "inspection"){
for(var i=0; i<doc.issues.length; i++) {
emit(doc.issues[i].id, {id: doc.issues[i].id, status: doc.issues[i].status, date: doc.date});
}
}
}
I'm using the id property of each issue as the key to be able to filter the results later by issue.
This works properly and returns 4 states for states for the same issue with different dates as follows:
{"total_rows":4,"offset":0,"rows":[
{"id":"31cc62d44e1723f4e39757758101a79a","key":"31cc62d44e1723f4e397577581019612","value":
{"id":"31cc62d44e1723f4e397577581019612","status":"pending","date":"2015-09-02"}},
{"id":"31cc62d44e1723f4e39757758101f808","key":"31cc62d44e1723f4e397577581019612","value": {"id":"31cc62d44e1723f4e397577581019612","status":"pending","date":"2015-09-16"}},
{"id":"31cc62d44e1723f4e39757758102f70e","key":"31cc62d44e1723f4e397577581019612","value": {"id":"31cc62d44e1723f4e397577581019612","status":"pending","date":"2015-11-01"}},
{"id":"31cc62d44e1723f4e397577581033cab","key":"31cc62d44e1723f4e397577581019612","value": {"id":"31cc62d44e1723f4e397577581019612","status":"cancelled","date":"2015-12-07"}}
]}
The problem is that I'm trying to run a reduce function to return only the latest issue and I'm unable to loop through all the values.
Although I have 4 rows returned from the map function above the length of the values parameter in the reduce function is 3 using the code below:
function (keys, values, rereduce) {
return values.length
}
{"rows":[
{"key":null,"value":3}
]}
Also when I try to return the values unchanged to see what's going on I noticed that two of the values have been grouped together as follows:
{"rows":[
{"key":null,"value":[
[{"id":"31cc62d44e1723f4e397577581019612","status":"pending","date":"2015-11-01"},
{"id":"31cc62d44e1723f4e397577581019612","status":"pending","date":"2015-09-02"}],
[{"id":"31cc62d44e1723f4e397577581019612","status":"cancelled","date":"2015-12-07"}],
[{"id":"31cc62d44e1723f4e397577581019612","status":"pending","date":"2015-09-16"}]]}
]}
Notice that the first two objects have been grouped together in a single array.
I'm really confused and I think it's a simple task but I can't figure out what I'm missing here..
I tried to loop through the values param to compare the date attribute, but that didn't work.
I also used the code below to search for the id attribute recursively but it also failed:
function (keys, values, rereduce) {
var res = [];
function extractVal(obj) {
if(obj.id) {
res.push(obj.id);
}else {
for(key in obj) {
extractVal(obj[key]);
}
}
}
extractVal(values);
return res;
}

Ok, This is what I figured out and please correct me if I'm wrong.
The reduce function runs several times with the rereduce value = false, and finally it runs on last time with the rereduce value = true.
So if I just returned the values array as it is in the condition where rereduce is false I will get an array of those returned arrays as the values parameter in the final step where the rereduce = true.
And therefore to extract the objects that were returned in the map function I need to run a nested loop as follows:
function (keys, values, rereduce) {
var arr=[];
if(rereduce){
for(var i=0; i<values.length; i++) {
for(var j=0; j<values[i].length; j++) {
arr.push(values[i][j]);
}
}
return arr;
} else{
return values;
}
}
And finally instead of just returning the arr parameter I will process it to filter whaterver should be returned by the reduce function.

Related

Conditional response in a map chained to a filter that may return an empty array

I have filter and map function chained. I need to do something conditional on whether a filter returns an empty array or not. However the map function on the array does not seem to be invoked if the filter returns an empty array.
const letters = ["a", "b", "c"];
const numbers = [1, 2, 3]
function result (arr) {
arr.filter((x) => {return x === "a"}).map((y, i, arr) => {
if(arr.length === 0) {
return //do something
} else {
return //do something else
}})
}
Is this expected or am I doing something wrong?
I was expecting the filter result to be passed to the map function, which can be used as the 3rd argument of the map function: map(item, index, array)
Here's a JSFiddle of the problem
https://jsfiddle.net/sub3z0xh/
You’re right about what’s happening. Array methods run once per element in the source array. If the source array is empty, it doesn’t run.
This isn’t new or working different with array methods vs a basic for loop. Example:
const arr = [];
for (let i = 0; i < arr.length; i++) {
console.log(“this code never runs because there are no elements to loop”);
}
So maybe just store the result of the filter in a variable instead. Get rid of the chained map since it may not run. Check the size/contents of your filtered array, then do stuff with that.

Backwards loop only printing undefined

I am attempting to create a function that can take in an array and display its contents backwards. I am having trouble with understanding why my function call is showing undefined when I enter an array in its parameter.
var arrayOne = []
function printReverse(arrayOne) {
for(var i = arrayOne.length-1; i < 0; i--) {
console.log(arrayOne[i])
}
}
There is a misunderstading with your question:
What you want to achieve is console.log elements on screen, not return anything.
Your code
var arrayOne = []
function printReverse(arrayOne) {
for(var i = arrayOne.length-1; i < 0; i--) {
console.log(arrayOne[i])
}
}
Does not work because you have a wrong operator in your code at i < 0. This will return false at first iteration, because i will be arrayOne.length, which would be > 0 if there is any element on it.
Change this part to i >= 0 and your code will work and actually print the values on console.
However, if you really want to have a reverted array, then you should simply use Array reverse() instead of writing a function to return it.
so there are some fundamentals that are off there. as stated in another answer i will never be less than 0 because you are defining it as a value greater than 0 in your for loop. Give something like this a try
EDIT: the comments are correct in the sense that the array will be mutated so make a copy of the array first which I've added using the spread operator
Also as far as this returning undefined -- it should return undefined unless you comment out the return statement
const arrayOne = [];
function printReverse(array) {
if (!Array.isArray(array) && array.length === 0 ) {
return 'The array is empty';
}
const arrCopy = [...array];
// technically you could just reverse it
// if you return it you have to assign it to someone on the function call
// return arrCopy.reverse();
// if you want to log the reversed array you could also
// console.log(arrCopy.reverse());
// if you want to reverse it then log each single index
// arrCopy.reverse().forEach(function(item) {
// console.log(item);
// })
}
// if you were to just return the reversed array you would have to assign it to a variable
// this is just an example and wouldnt technically work because arrayOne is empty
// also if you use this YOU HAVE TO RETURN THE ARRAY COPY
// const reversedArray = printReverse(arrayOne);
If you want it to return something, you have to add a return within the function, such that
function printReverse(arrayOne) {
for(var i = arrayOne.length-1; i < 0; i--) {
console.log(arrayOne[i]);
}
return "";
}
However, in your case, this doesn't make a lot of sense. You can only return one thing, be it a String, int, array, object, whatever. But once your program hits one return statement, it will quit the function after returning the value.

JavaScript function that takes an array as a parameter

I am trying to create a JavaScript function that takes an array as a parameter and returns the first item in the array. This should work for an array of any size. Here is what I have so far, it appears to work just fine in the console but my instructor says there's a better way to do this:
var array = [];
function numbaOne(array) {
for (var i = 0; i < array.length; i++) {
console.log(array[0])
};
}
Any help would be appreciated. I've read about data structures and arrays but can't figure out how to simplify or make this better.
What you are doing is looping over the array and printing out the first item each time. You just want:
var array = [...];
function numbaOne(array) {
console.log(array[0]); // Print out the first value of the array
return array[0]; // Return the first value of the array
}
There is one edge case here. If the array is empty, then the function will fail because array[0] will be undefined.
So, a more complete version might be:
var array = [...];
function numbaOne(array) {
if(array.length > 0) { // Check if there is anything in the array
console.log(array[0]);
return array[0];
} else { // If there isn't, let's return something "bad"
console.log("The array is empty!");
return undefined;
}
}

Merge array into a single array

If this were .NET, I'd ask how to convert List<List<MyClass> to List<MyClass>. However, I'm not very good with javascript and don't know how to ask that as a question using Javascript terminology!
My javascript object comes through like
And is created as:
js_datasets.push({
"DataItem0": {
lzabel: "This",
data: [[1408710276000, null],[1408710276000, 15]]
},
"DataItem1": {
lzabel: "That",
data: [[1408710276000, null],[1408710276000, 15]]
},
});
js_datasets.push({
"DataItem22": {
lzabel: "And other",
data: [[1408710276000, null],[1408710276000, 5]]
},
"DataItem23": {
lzabel: "And lastly",
data: [[1408710276000, null],[1408710276000, 1]]
},
});
Each object is the same "type" (if it matters).
I'd like to create a single list but I am failing to do so. My efforts are
var myDataSet = []; //this is the results of what I want, ideally as a single list
for (var i = 0; i < js_datasets.length; i++) {
if (i==0) {
myDataSet.push(js_datasets[i]);
}
else {
myDataSet.concat(js_datasets[i]);//does nothing
myDataSet.join(js_datasets[i]);//does nothing
}
...more logic
As you can see with the above, I've tried using push, concat and join.
If I update the code to only use push (and never use concat and join) then I get all the values I want, but again, as an array within an array.
Using concat and join do not add to the list.
So, if we can assume the 12 items in the array (pictured) all contain 10 items, I'd like to have a single list of the 120 items!
How can I simply convert this multidimension array (is it multidimension) to a single dimension array.
This will be a bit complicated, as the items in your Array js_datasets are not Arrays, but a more generic Object. This means you can't assume the keys will be in order if you try to read them
Lets write some helper functions to account for this;
function dataItemCollectionToArray(o) {
var keys = Object.keys(o);
// assuming no non-DataItem keys, so next line commented out
// keys = keys.filter(function (e) {return e.indexOf("DataItem") === 0;});
keys.sort(function (a, b) { // ensure you will get the desired order
return +a.slice(8) - +b.slice(8);
});
return keys.map(function (e) {return o[e];});
}
Now you can loop over js_datasets performing this conversion
var myDataSet = [], i;
for (i = 0; i < js_datasets.length; ++i) {
// assuming no gaps, if you need to add gaps, also find min, max indices
// in `dataItemCollectionToArray`, and check them in each iteration here
myDataSet.push.apply(myDataSet, dataItemCollectionToArray(js_datasets[i]));
}
Please note that Object.keys and Array.prototype.map may require polifills if you wish to support old browsers, i.e. IE<=8
An easier solution however, may be to re-write how js_datasets is constructed so that the Objects you are pushing are more Array-like or indeed pushing true Arrays, perhaps with a couple extra properties so you know the offset for the first index. This would mean you can use flatten methods that you'll find around the internet

Re-order Json array by key value

I have a contact list that is returned to me in this very long form. It is getting returned Based on order of entry (the field outside the first set of brackets, indented). The problem I'm having is I want it to order alphabetically by displayName. Since that is in it's own array inside of the main one I'm having trouble getting the full array to reorder by it. Can anyone figure this out? Thanks. Oh and it's got to be done in JS.
{
"0":
{"id":1,"rawId":null,"displayName":"Person 1","name":null,"nickname":null,"phoneNumbers":[{"type":"mobile","value":"phonenumb53534r","id":0,"pref":false}],"emails":null,"addresses":null,"ims":null,"organizations":null,"birthday":null,"note":null,"photos":null,"categories":null,"urls":null},
"1":
{"id":2,"rawId":null,"displayName":"Person 2","name":null,"nickname":null,"phoneNumbers":[{"type":"mobile","value":"phonenumber535345","id":0,"pref":false}],"emails":null,"addresses":null,"ims":null,"organizations":null,"birthday":null,"note":null,"photos":null,"categories":null,"urls":null},
"2":
{"id":3,"rawId":null,"displayName":"Person 3","name":null,"nickname":null,"phoneNumbers":[{"type":"mobile","value":"phonenumber47474","id":0,"pref":false}],"emails":null,"addresses":null,"ims":null,"organizations":null,"birthday":null,"note":null,"photos":null,"categories":null,"urls":null}, goes on for a couple hundred rows
Objects in JavaScript are not ordinal by nature. If you have an array, you can work with that. Otherwise, you have to convert the outer part of the object into an array yourself:
var arrayOfObj = [];
for (item in obj) {
if (obj.hasOwnProperty(item)) {
arrayOfObj.push(obj[item]);
}
}
If you can do that before you even get the JSON, so much the better. Once you have that, you can just use the normal array .sort method
arrayOfObj.sort(function (a, b) {
if (a.displayName < b.displayName) {
return -1;
}
else if (a.displayName > b.displayName) {
return 1;
}
return 0;
});
http://jsfiddle.net/ZcM7W/
You'll need to parse that responseText into JSON. But since it's returned as an object literal you'll have to convert it to an array. Then you can sort it with a custom comparator function.
var json = JSON.parse(response),
data = [];
for (key in json) {
data.push(json[key]);
}
data.sort(function (a, b) {
return a.displayName > b.displayName;
});

Categories