How to use map() and reduce() functions in Javascript? - javascript

I am writting a simple function that would allow me to calculate prime numbers on one of nosql databases. After multiple approaches, i got an error that value i am looking for is not defined, thus I would appreciate your feedback.
Here is what i have tried:
First I have generated a set of numbers:
for (var i = 0; i < 1000; i++) db.exemplary.insert( {x: Math.random()} );
2.Secondly I have defined map function
map = function() {
for (var i = 2; i < x; i++){
if(x % i == 0)
try {} catch (e) {};
}
emit(i, value);
};
In the end the reduce function:
reduce = function (i,value){return array.sum(value)}
I assigned the collection to variable and called the function:
collection = db.exemplary
var result = collection.mapReduce(map, reduce, {out: {inline: 1}});
As per my begginer understanding the map step should check whether the number is prime or not.
Reduce step on the other hand should sum all occurrences of prime numbers.
I got error that x is not defined, but it is present in the db.exemplary collection.
I would appreciate every improvement hint/suggestion for above functionality.
EDIT: Currently my function does not "emit" any results of map operation, working on this bit now.

Math.random() generates by default float numbers from 0 to <1.
then in your generator you should use a function like this, for example to get random numbers from 0 to 999 :
{ x: Math.floor(Math.random()*1000) }

Related

Unable to pass an array as argument of a javascript function

I'm trying to implement the quickSort algorithm in javascript, i have to extract 10,000 numbers from a txt file, pass them into an array, and pass this as an argument of my quickSort function, using the fs module of nodejs. The code is able to read the 10,000 numbers, and to convert them from an array of string to an array of number, but when i try to pass the array into my function, only 3472 numbers are passed, which i don't understand.
const fs = require('fs');
// Reading the data from the file containing the 10,000 numbers
const file = fs.readFileSync('./quickSort.txt', 'utf-8');
//Checking if it has read all the numbers correctly
console.log(file); // Displays the 10,000 numbers as strings in an array
// Convert them from string to integer
const finalFile = file.split('\n').map(e => {
return parseInt(e, 10);
})
// Checking if it has converted each element of the array to an integer
//console.log(finalFile) displays the array, with the 10,000 elements converted to integers
// Initialize a counter for the comparaisons made by the quickSort algorithm
let comparisons = 0;
// Sort them using quick sort
function quick_Sort(origArray) {
if (origArray.length <= 1) {
return origArray;
} else {
// Checking if the array has been correctly passed as an argument
console.log(origArray.length); //Displays 3742 instead of 10,000
var left = [];
var right = [];
var newArray = [];
var pivot = origArray.pop();
var length = origArray.length;
// I have tried comparisons += length - 1; too, but i doesn't work
comparisons += length;
for (var i = 0; i < length; i++) {
if (origArray[i] <= pivot) {
left.push(origArray[i]);
} else {
right.push(origArray[i]);
}
}
for (var i = 0; i < right.length; i++) {
comparisons++;
if (right[i] < pivot) {
return right.splice(i, 0, pivot);
}
}
return newArray.concat(quick_Sort(left), quick_Sort(right));
}
}
// Display the result
const result = quick_Sort(finalFile);
// expected output: 25
console.log(result);
Thank you very much.
Edit: In fact the problem of the size comes from the last for loop of the function, if i delete it, and insert the pivot between like that, it works (thanks to StardustGogeta) :
return newArray.concat(quick_Sort(left), pivot, quick_Sort(right));
This is a logical error. You need to change
return newArray.concat(quick_Sort(left), quick_Sort(right));
to
return newArray.concat(quick_Sort(left), pivot, quick_Sort(right));
With that change, the program works for me. The problem is that you are accidentally getting rid of (via .pop()) approximately 1/3 of your input values (the pivot values) during sorting.
try this:
const finalFile = file.split('\r?\n').map(.....)
Your parsing code works for me except for one issue: parseInt returns NaN for the last new line so you need to remove the last element from the array like this: finalFile.pop();. However this does not explain why you are seeing such a difference in the number of elements. There must be something different either in the code or the file you posted.

Tensorflow.js Please make sure the operations that use variables are inside the function f passed to minimize()

I have started to use javascript and TensorFlow.js to work on some machine learning projects, I am working on creating a linear regression model, however, I cannot figure out what is causing this error
Can not find a connection between any variable and the result of the loss function y=f(x). Please make sure the operations that use variables are inside the function f passed to minimize()."
I have created two Tensors
globalTensorXs = tf.tensor2d(globaArrayXs); //input data
globalTensorYs = tf.tensor1d(globaArrayYs); //y output
I have created the coefficients/weights as below as an array of tf scalars.
function createWeights(_numWeights)
{
for ( var x = 0; x < _numWeights; x++)
{
globalWeightsTensorArr.push(tf.variable(tf.scalar(Math.random())));
}
}
There is A training function which I pass the x and y Tensors into, it is the call to the optimise.minimize that causes the issue. it does not detect the variable for training, which are stored in globalWeightsTensorArr
async function train(xsTensor, ysTensor, numIterations)
{
/*//////OPTIMISER.MINIMISE/////////////
Minimize takes a function that does two things:
It predicts y values for all the x values using the predict
model function.
It returns the mean squared error loss for those predictions
using the loss function. Minimize then automatically adjusts any
Variables used by thi predict/loss function in order to minimize
the return value (our loss), in this case the variables are in
"globalWeightsTensorArr" which contains the coefficient values
to be altered by the modeld during "numIterations" iterations of
SGD.
*/
for (let iter = 0; iter < numIterations; iter++)
{
optimiser.minimize(function ()
{
return loss(predict(xsTensor), ysTensor);
}, globalWeightsTensorArr);
}
}
// the predict and loss function are here...
//The following code constructs a predict function that takes inputs(X's) //and returns prediction Y: it represents our 'model'. Given an input //'xs' it will try and * predict the appropriate output 'y'.
function predict(_Xs)
{
return tf.tidy(() => {
for ( var x = 0; x < 8; x++)
globalWeightsArr[x] = globalWeightsTensorArr[x].dataSync();
const weightTensor = tf.tensor1d(globalWeightsArr);
const prediction = tf.dot(_Xs, weightTensor);
return prediction;
});
}
//The loss function takes the predictions from the predict function
//and the actual lables and adjusts the weights
//the weights are considered to be any tensor variable that impact the //function We can define a MSE loss function in TensorFlow.js as follows:
function loss(_predictedTensor, _labels)
{
const meanSquareError =_predictedTensor.sub(_labels).square().mean();
return meanSquareError ;
}
can anyone please help explain the problem?
Regards
Aideen
We resolved the issue by changing the way the weights/coefficients were created. Now minimize can detect the variables used by predict, and it adjusts them accordingly. later I will post the entire solution to codepen. still learning!
function createWeights(_numWeights) {
const randomTensor = tf.randomUniform([_numWeights, 1]);
globalWeightsTensorVar = tf.variable(randomTensor);
}
here is the predict function used b
function predictLogical(_Xs) {
return tf.dot(_Xs, globalWeightsTensorVar);
}
The issue is related to tf.variable. One needs to use tf.variable to create the weights that will be updated by the function created by optimiser.minimize().
A variable created by tf.variable is mutable contrary to tf.tensor that is immutable. As a result if one uses tf.tensor to create the weights they could not be updated during the training

Higher Order Functions - Eloquent JS

I have been reading through Chapter 5 last night and throughout the morning and can't seem to get the higher order functions concepts to stick. Here are the examples:
//I understand this first function, I am including it because it is used in the next function.
function forEach(array, action) {
for (vari = 0; i < array.length; i++)
action(array[i]);
}
forEach(["Wampeter", "Foma", "Granfalloon"], print);
function sum(numbers) {
var total = 0;
forEach(numbers, function(number) {
total += number;
});
return total;
}
To my understanding the function sum is taking the argument numbers, which I believe comes in as an array? Now, when the forEach function is called (within sum), it takes the array numbers passed to sum and then it also takes an anonymous function?
I am really confused on what this anonymous function is actually doing. It is taking the parameter number but what else is it doing? Does this anonymous function imply that in that parameter, a function like print or show will be passed the parameter number? In other words it would look something like this
function([10,12,11]) {
var total = 0
forEach([10,12,11]), show(???)
//at this point it would iterate over the array, and use the action passed to display `//the pointer in the array. What I think is happening is that it is taking this pointer value and adding it to the total.` //
I have been trying to wrap my head around this example for a while, if anyone knows of a good explanation or any other documentation to read over I would greatly appreciate it, thanks!
The anonymous function is applied to every currently selected element. You can see better how this works if you unroll (execute stepwise) the loop (pseudocode, * means current element):
var total = 0;
forEach([*1, 2, 3]), fun(1)) => total = 0 + 1 = 1
forEach([1, *2, 3]), fun(2)) => total = 1 + 2 = 3
forEach([1, 2, *3]), fun(3)) => total = 3 + 3 = 6
You can rewrite the sum function like this:
// because there is no "pass by reference" in JavaScript for
// "simple" types, total must be wrapped in an object
// in order to return the sum through the parameter for the showcase
var result = { total: 0 }
function sum(numbers_array) {
for (var i = 0; i < numbers_array.length; i++) {
accumulate(result, numbers_array[i]);
}
}
function accumulate(acc, number) {
acc.total += number;
}
In this case the accumulate function does the same as the anonymous function. When the accumulate function is declared within the scope of the sum function, then the total variable is like global (it is known) to the accumulate function and then there is no need of the first parameter, so the function becomes like the one you already know:
var total = 0;
function sum(numbers_array) {
function accumulate(number) {
total += number;
}
for (var i = 0; i < numbers_array.length; i++) {
accumulate(numbers_array[i]);
}
}
Next step would be to extract and pass the accumulate function as parameter:
var total = 0;
function accumulate(number) {
total += number;
}
// notice, that JavaScript knows how many parameters your function expects
function sum(numbers_array, action) {
for (var i = 0; i < numbers_array.length; i++) {
action(numbers_array[i]);
}
}
What left is to extract the iteration and the code will look like this one in the book.
Let me see if I can explain this easily for you:
The forEach() function accepts two parameters, the first one called array is obviously an array or an array-like object, the second parameter called action is actually a function.
forEach() visits each element in the array passed to it and applies to each element in the array the function passed to it as the second parameter.
So forEach() calls the function passed to it named action for each element in the array and it gives the function the array element as a parameter.
The function sum(numbers) accepts an array as you have though, and it uses forEach() inside itself to calculate the sum of numbers in that array using the anonymous function.
Remeber that the anonymous function is called once for each element in the array passed to sum() so it actually sums the elements in the array.
In simple words : to make your code more generic and concise.
Ex:
Lets say we want to find the max element in an Array :
That's pretty easy and cool :
In java script we will write :
var array = [10,20,30,40,50,60]
function maxEle(array){
var max = array[0];
for(var i=0;i< array.length;i++){
if(max < array[i]){
max = array[i];
}
}
console.log(max);
}
So this will give me the maximum element in an array.
Now after few days, some one asked me that your max is working pretty cool, I want a function which will print the minimum in an array.
Again I will redo the same thing, which i was doing in finding Max.
function minEle(array){
var min = array[0];
for(var i=0;i< array.length;i++){
if(min > array[i]){
min = array[i];
}
}
console.log(min);
}
Now this is also working pretty cool.
After sometime, another requirement comes up : I want a function which will print the sum of all the elements of the array.
Again the code will be similar to what we have written till now, except now it will perform summation.
function sumArr(array){
var sum = 0;
for(var i=0;i< array.length;i++){
sum = sum + array[i];
}
}
console.log(sum);
}
Observation :
After writing these bunch of codes, I m rewriting almost the same thing in every function, iterating over the Array and then performing some action.
Now writing the repetitive code is not a cool stuff.
Therefore we will try to encapsulate the varying part i.e action viz min, max, summation.
Since its feasible to pass functions as arguments to a function in FPL.
therefore we will re-factor our previously written code and now write a more generic function.
var taskOnArr = function(array, task){
for(var i=0;i<array.length;i++){
task(array[i]);
}
}
Now this will be our generic function, which can perform task on each element of Array.
Now our tasks will be :
var maxEle = array[0];
var taskMaxEle = function(ele){
if(maxEle < ele){
maxEle = ele;
}
}
Similarly for min element :
var minEle = array[0];
var taskMinEle = function(ele){
if(minEle > ele){
minEle = ele;
}
}
Also for summation of Array :
var sum = 0;
var taskSumArr = function(ele){
sum = sum + ele;
}
Now we need to pass functions to taskOnArr function :
taskOnArr(array,taskSumArr);
console.log(sum);
taskOnArr(array,taskMinEle);
console.log(minEle);
taskOnArr(array,taskMaxEle);
console.log(maxEle);

The minimum even value in the array

So, I have this program that asks for the minimum even value in the array and I have written the code but I seem to missed a loop. I will write the correct code but I hope someone would explain why is there a while loop
<HTML>
<HEAD>
<SCRIPT LANGUAGE = "JavaScript">
var number=new Array(10)
for(var i=0; i<number.length; i=i+1)
{
number[i] =window.prompt('enter number ','')
number[i] =parseFloat(number[i])
}
var y = 0
while (number[y] % 2 != 0) //get the first even number in the array
{
y = y + 1
}
//after you exit the while loop y will have the index of the first even number
var Min
Min = number[y]
for(var i=0; i<number.length; i=i+1)
{
if (number[i] % 2 == 0)
{
if(number[i]<Min)
{
Min= number[i]
}
}
}
document.write(Min)
</SCRIPT>
</HEAD>
</HTML>
So, this part
var y = 0
while (number[y] % 2 != 0) //get the first even number in the array
{
y = y + 1
}
//after you exit the while loop y will have the index of the first even number
I'm finding it hard to really grasp this loop and if I might ask: is there another way to find the minimum value in an array?
Many thanks!
The while loop sets the first value of Min so that subsequent comparisons work. Here's a far
simpler and faster way to do the same thing:
var min = Infinity; // Start with the biggest number possible
for (var i=myArray.length;i--;){
var val = myArray[i];
if (val<min && val%2==0) min = val;
}
This is faster because—unlike the original code—this doesn't iterate over the first non-even values twice. It would be roughly equivalent in speed if the for loop in the original started at index y, i.e. for (var i=y+1;i<number.length;++i)
It's also very slightly faster because the for loop caches the length of the array instead of looking it up each time, and because it only looks up the value in the array once each loop, not three times. Modern JavaScript runtimes like V8 can optimize naive code to behave similarly, however, so this is not a very important point.
Edit: For fun, here's a modern, functional programming approach:
var min = Math.min.apply(Math,myArray.filter(function(n){ return n%2==0 }));
The above uses Array.filter to create a new array of just the even-valued items, and then uses Function.prototype.apply to pass the array of values as parameters to Math.min.
If you're interested how to do that in modern Javascript, it goes like this:
minEvenElement = Math.min.apply(Math, myArray.filter(function(e) { return !(e % 2) }))

alternatives for excessive for() looping in javascript

Situation
I'm currently writing a javascript widget that displays a random quote into a html element. the quotes are stored in a javascript array as well as how many times they've been displayed into the html element. A quote to be displayed cannot be the same quote as was previously displayed. Furthermore the chance for a quote to be selected is based on it's previous occurences in the html element. ( less occurrences should result in a higher chance compared to the other quotes to be selected for display.
Current solution
I've currently made it work ( with my severely lacking javascript knowledge ) by using a lot of looping through various arrays. while this currently works ( !! ) I find this solution rather expensive for what I want to achieve.
What I'm looking for
Alternative methods of removing an array element from an array, currently looping through the entire array to find the element I want removed and copy all other elements into a new array
Alternative method of calculating and selecting a element from an array based on it's occurence
Anything else you notice I should / could do different while still enforcing the stated business rules under Situation
The Code
var quoteElement = $("div#Quotes > q"),
quotes = [[" AAAAAAAAAAAA ", 1],
[" BBBBBBBBBBBB ", 1],
[" CCCCCCCCCCCC ", 1],
[" DDDDDDDDDDDD ", 1]],
fadeTimer = 600,
displayNewQuote = function () {
var currentQuote = quoteElement.text();
var eligibleQuotes = new Array();
var exclusionFound = false;
for (var i = 0; i < quotes.length; i++) {
var iteratedQuote = quotes[i];
if (exclusionFound === false) {
if (currentQuote == iteratedQuote[0].toString())
exclusionFound = true;
else
eligibleQuotes.push(iteratedQuote);
} else
eligibleQuotes.push(iteratedQuote);
}
eligibleQuotes.sort( function (current, next) {
return current[1] - next[1];
} );
var calculatePoint = eligibleQuotes[0][1];
var occurenceRelation = new Array();
var relationSum = 0;
for (var i = 0; i < eligibleQuotes.length; i++) {
if (i == 0)
occurenceRelation[i] = 1 / ((calculatePoint / calculatePoint) + (calculatePoint / eligibleQuotes[i+1][1]));
else
occurenceRelation[i] = occurenceRelation[0] * (calculatePoint / eligibleQuotes[i][1]);
relationSum = relationSum + (occurenceRelation[i] * 100);
}
var generatedNumber = Math.floor(relationSum * Math.random());
var newQuote;
for (var i = 0; i < occurenceRelation.length; i++) {
if (occurenceRelation[i] <= generatedNumber) {
newQuote = eligibleQuotes[i][0].toString();
i = occurenceRelation.length;
}
}
for (var i = 0; i < quotes.length; i++) {
var iteratedQuote = quotes[i][0].toString();
if (iteratedQuote == newQuote) {
quotes[i][1]++;
i = quotes.length;
}
}
quoteElement.stop(true, true)
.fadeOut(fadeTimer);
setTimeout( function () {
quoteElement.html(newQuote)
.fadeIn(fadeTimer);
}, fadeTimer);
}
if (quotes.length > 1)
setInterval(displayNewQuote, 10000);
Alternatives considered
Always chose the array element with the lowest occurence.
Decided against this as this would / could possibly reveal a too obvious pattern in the animation
combine several for loops to reduce the workload
Decided against this as this would make the code to esoteric, I'd probably wouldn't understand the code anymore next week
jsFiddle reference
http://jsfiddle.net/P5rk3/
Update
Rewrote my function with the techniques mentioned, while I fear that these techniques still loop through the entire array to find it's requirements, at least my code looks cleaner : )
References used after reading the answers here:
http://www.tutorialspoint.com/javascript/array_map.htm
http://www.tutorialspoint.com/javascript/array_filter.htm
http://api.jquery.com/jQuery.each/
I suggest array functions that are mostly supported (and easily added if not):
[].splice(index, howManyToDelete); // you can alternatively add extra parameters to slot into the place of deletion
[].indexOf(elementToSearchFor);
[].filter(function(){});
Other useful functions include forEach and map.
I agree that combining all the work into one giant loop is ugly (and not always possible), and you gain little by doing it, so readability is definitely the winner. Although you shouldn't need too many loops with these array functions.
The answer that you want:
Create an integer array that stores the number of uses of every quote. Also, a global variable Tot with the total number of quotes already used (i.e., the sum of that integer array). Find also Mean, as Tot / number of quotes.
Chose a random number between 0 and Tot - 1.
For each quote, add Mean * 2 - the number of uses(*1). When you get that that value has exceeded the random number generated, select that quote.
In case that quote is the one currently displayed, either select the next or the previous quote or just repeat the process.
The real answer:
Use a random quote, at the very maximum repeat if the quote is duplicated. The data usages are going to be lost when the user reloads/leaves the page. And, no matter how cleverly have you chosen them, most users do not care.
(*1) Check for limits, i.e. that the first or last quota will be eligible with this formula.
Alternative methods of removing an array element from an array
With ES5's Array.filter() method:
Array.prototype.without = function(v) {
return this.filter(function(x) {
return v !== x;
});
};
given an array a, a.without(v) will return a copy of a without the element v in it.
less occurrences should result in a higher chance compared to the other quotes to be selected for display
You shouldn't mess with chance - as my mathematician other-half says, "chance doesn't have a memory".
What you're suggesting is akin to the idea that numbers in the lottery that haven't come up yet must be "overdue" and therefore more likely to appear. It simply isn't true.
You can write functions that explicitly define what you're trying to do with the loop.
Your first loop is a filter.
Your second loop is a map + some side effect.
I don't know about the other loops, they're weird :P
A filter is something like:
function filter(array, condition) {
var i = 0, new_array = [];
for (; i < array.length; i += 1) {
if (condition(array[i], i)) {
new_array.push(array[i]);
}
}
return new_array;
}
var numbers = [1,2,3,4,5,6,7,8,9];
var even_numbers = filter(numbers, function (number, index) {
return number % 2 === 0;
});
alert(even_numbers); // [2,4,6,8]
You can't avoid the loop, but you can add more semantics to the code by making a function that explains what you're doing.
If, for some reason, you are not comfortable with splice or filter methods, there is a nice (outdated, but still working) method by John Resig: http://ejohn.org/blog/javascript-array-remove/

Categories