function return the same value - javascript

N_ALPHA = 6;
N_CHOICES = 4;
ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var alphabet = ALPHABET.substring(0, N_ALPHA);
var indexForm=new Array();
function guessStrToArr(inStr)
{
{
for (i=0;i<N_CHOICES;i++)
{
indexForm[i]=alphabet.indexOf(inStr.charAt(i).toUpperCase());
}
}
return indexForm;
}
function numBulls(guess, goal)
{
guess=new Array (guessStrToArr(prompt('enter your guess1')));
alert(guess);
goal=new Array(guessStrToArr(prompt('enter your guess2')));
var checkArray = new Array (guess.concat(goal);
alert(checkArray);
var count=0;
for (i=0;i<N_CHOICES;i++)
{
if (guess[i]===goal[i])
{
count++
}
}
return count;
}
numBulls();
when I run the above code, it returnt the same array, evern I type different code into prompt alet box. I don't know why, can you please help me?
Thank you very much.

indexForm is a global variable. When you call the guessStrToArr function for the first time array gets populated. The second time it gets repopulated. When you're doing the comparison, your comparing the array against itself. Try this:
function guessStrToArr(inStr) {
var indexForm = new Array();
for (i = 0; i < N_CHOICES; i++) {
indexForm[i] = alphabet.indexOf(inStr.charAt(i).toUpperCase());
}
return indexForm;
}
Also note that you are making no attempt to ensure that inStr.length is the same as N_CHOICES.

Related

faild to move the element in between?

i have been try to solve the sudoku with Blacktracking algo, everything is good, canvar is called and i able to see the number but the things is number are not moving i.e the logic is not exectuing
current.i === 0; is where i'm get the error! even i have declared a sperate variable for the num also the problem is not sloved. only if i remove the .num current == 0 than its not showing any error but still the number is not moving
enter image description here
var cell = [];
var stack = [];
var sudoku = [2,3,0,9,4,0,6,7,0,
8,0,0,3,2,5,9,1,4,
9,0,0,7,6,0,3,2,0,
1,0,0,0,0,0,7,9,2,
5,0,3,2,1,0,4,8,6,
4,0,0,6,8,0,5,3,1,
7,0,0,1,0,0,0,0,9,
6,5,9,8,7,2,1,4,3,
3,0,0,0,9,0,0,0,7];
var current;
var number = 1;
function setup(){
createCanvas(450,450);
var a=0;
var b=0;
for(var i=0;i<81;i++){
if(a%9==0 && i!=0){
b = b+50;
a = 0;
}
each[i] = new each(a,b,i,sudoku[i]);
a = a+50;
}
current = cell[0];
}
function draw(){
background(10);
for(var i=0;i<81;i++){
each[i].show();
}
if(current.num === 0){ //the error is typeerror can't read the property of num
if(! sameColumn(current.i,number) && ! sameRow(current.i,number) && ! sameSquare(current.i,number) && number<(10)){
current.num = number;
stack.push(current);
number = 0;
current.each[current.i+1];
}
else {
if(number > 8){
current.num = 0;
current = stack.pop();
number = current.num;
current.num = 0;
}
}
}
else{
current = each[current+1];
number = 0;
}
number++;
}
function each(a,b,i,num){
this.a = a;
this.b = b;
this.i = i;
this.num = num;
this.show = function(){
noFill();
stroke(255);
rect(this.a,this.b,50,50);
textSize(32);
text(this.num,a+12,b+40);
}
}
The error is pretty much straight forward. current = cell[0]; becomes undefined since you defined cell as an empty array and didn't manipulated it after that.
From what I have observed so far, many parts of your code logically does not work, for example,
same Column(current.i,number) && ! sameRow(current.i,number) && ! sameSquare(current.i,number)
will definitely throw you an error is it is executed (it is not since the execution does not reach to that line), unless you have a separate js file that contains these functions.
Another one is
current = cell[current+1];
if the current variable is to store the cell object, it does not make sense to add 1 to it, and vice versa.
Now I believe this is how setup function was meant to look like:
function setup(){
createCanvas(450,450);
var a=0;
var b=0;
for(var i=0;i<81;i++){
if(a%9==0 && i!=0){
b = b+50;
a = 0;
}
cell[i] = new Cell(a,b,i,sudoku[i]); //changed each[i] to cell[i], also renamed the 'each' class
a = a+50;
}
current = cell[0];
}
If possible, please edit in a little more information about what exactly does your code do. Cheers :)

how to get incremented value in for loop after callback function in javascript?

My Requirement:
I want to get the list of values using for loops. In for loop one iteration completed one time then the callback will send that list of values(array).
Once the first iteration completed second time loop value should be get incremented value.
For example : 5 values
after 5th iteration then loop is over. then second time loop should start with '0' but here it's starting with last incremented value. please help me to achieve this.
Below code is working fine for the first time.
Callback function:
$inventoryManagement.getObjectNameAndAttributeAndDataTypeIdUsingObjectAndAttributeId(objectId,attributeId, function(objectAttributeBlockElement) {
//$scope.val = myOwnJ;
console.log(objectAttributeBlockElement);
});
Function:
var myOwnJ = 0;
// Getting ObjectId And AttributeId Using CellId For Normal Controls
var getObjectNameAndAttributeAndDataTypeIdUsingObjectAndAttributeId = function(objectId,attributeId, callback) {
var objectAttributeBlockElement = [];// one array
try {
// iterate over the objectAttributes
for (var i = 0; i < pageObject.objects.length; i++) {
if (pageObject.objects[i].id == objectId) {
var name = "";
var labelName = "";
var dataTypeId = "";
for (;myOwnJ < pageObject.objects[i].objectAttribute.length;) {
name = pageObject.objects[i].objectAttribute[myOwnJ].name;// got the current label name
labelName = pageObject.objects[i].objectAttribute[myOwnJ].labelName;// got the current name
dataTypeId = pageObject.objects[i].objectAttribute[myOwnJ].dataTypeId;// got the current dataTypeId
objectAttributeBlockElement.push(name,labelName,dataTypeId);
callback(objectAttributeBlockElement, myOwnJ++);
return;
}
}
}
throw {
message: "objectId not found: " + objectId
};
} catch (e) {
console.log(e.message + " in getObjectNameAndAttributeAndDataTypeIdUsingObjectAndAttributeId");
}
};
You could pass j as an additional function parameter, such as
var getObjectNameAndAttributeAndDataTypeIdUsingObjectAndAttributeId = function(objectId, attributeId, j, callback) {
so it won't be a local variable. Then, instead of declaring it locally, use the following:
for (j = ((j === null) ? 0 : j); j < pageObject.objects[i].objectAttribute.length; j++) {
That way, if you call your function with j, you'll get it incremented after each call.
Another approach, which I won't recommend, would be making j a global variable by declaring it ouside your function instead of passing it as a parameter. That way you don't have to modify your function declaration at all. If you're up to that, I strongly suggest modifying the variable name cause j would be too generic for a global scope variable and it will cause trouble sooner or later: use something like myOwnJ and you'll be fine.
EDIT: Full source code (as requested by the OP):
var myOwnJ = 0;
// Getting ObjectId And AttributeId Using CellId For Normal Controls
var getObjectNameAndAttributeAndDataTypeIdUsingObjectAndAttributeId = function(objectId,attributeId, callback) {
var objectAttributeBlockElement = [];// one array
try {
// iterate over the objectAttributes
for (var i = 0; i < pageObject.objects.length; i++) {
if (pageObject.objects[i].id == objectId) {
var name = "";
var labelName = "";
var dataTypeId = "";
if(myOwnJ < pageObject.objects[i].objectAttribute.length) {
name = pageObject.objects[i].objectAttribute[myOwnJ].name;// got the current label name
labelName = pageObject.objects[i].objectAttribute[myOwnJ].labelName;// got the current name
dataTypeId = pageObject.objects[i].objectAttribute[myOwnJ].dataTypeId;// got the current dataTypeId
objectAttributeBlockElement.push(name,labelName,dataTypeId);
callback(objectAttributeBlockElement, myOwnJ++);
return;
}
else {
myOwnJ = 0;
}
}
}
throw {
message: "objectId not found: " + objectId
};
} catch (e) {
console.log(e.message + " in getObjectNameAndAttributeAndDataTypeIdUsingObjectAndAttributeId");
}
};
What you are looking for is a global variable for 'j'. Although this is discouraged to be used.
var j=0;
var getObjectNameAndAttributeAndDataTypeIdUsingObjectAndAttributeId =
function(objectId, attributeId, callback) {
//do your stuff
//increment j
j++;
}

Efficient way to handle JS function ordering

I'm fairly new to JS and am still slightly confused, by the ordering and nesting of JS functions. I have a script that I want to occur in a specific way. The problem a criteria can be left blank by a user. Im trying to say if the variable length is greater than zero run the callback, but then move into the code that occurs under the next two if statements. I know there must be a more efficient method for this, but for the life of me I can't think of one besides placing all the other code under each different if/else statement.
var lst = []
var lst2 = []
var lst3 = []
alert(cityu);
alert(dateu);
alert(numberu);
d3.csv("kyle.csv", function (d) {
return {
city: d.from,
number: d.phone_number,
date: d.from_date
};
}, function (error, rows) {
if (dateu.length > 0) {
for (var i = 0; i < rows.length; i++) {
if (rows[i].date === dateu) {
lst.push(rows[i]);
console.log(rows[i]);
}
}
} else {
if (cityu.length > 0) {
for (var i = 0; i < lst.city.length; i++) {
if (lst.city[i] === cityu) {
lst2.push(lst[i]);
console.log(lst2);
}
}
} else {
if (numberu.length > 0) {
for (var i = 0; i < rows.length; i++) {
if (lst.number[i] === numberu) {
lst3.push(lst2[i]);
console.log(lst3);
}
}
}
}
}
})
};
Here you can see that if the dateu variable has length greater than zero the rows in a csv matching that user entered criteria will be pushed to the array "lst". Obviously it currently doesn't move into the next callback under, it will only do this if "dateu" equalled zero.
One other issue with my script is that at each if statement I hope to reduce my original input based on the user entered parameters. For example a user might enter "seattle" the variable "city" will now equal seattle and only rows containing Seattle as their city will be kept in the array that rows[i] is pushed to.
Every piece of user input shown here:
alert(cityu);
alert(dateu);
alert(numberu);
will have the same affect on the dataset, each time reducing the number of rows included.
The problem specifically is that each if statement relies on the array from the previous callback.
Your code redone a little - I've removed the else blocks, because you want to do each loop regardless of the previous loop
if(condition1) {
do something
}
else {
do something else
}
from that, if the first condition is met, the else block wont get executed
if(condition1) {
do something
}
if(condition2) {
do something else
}
In this case, do something else only relies on condition2 being true, consition1 is irrelevant
var lst = []
var lst2 = []
var lst3 = []
alert(cityu);
alert(dateu);
alert(numberu);
d3.csv("kyle.csv", function(d) {
return {
city: d.from,
number: d.phone_number,
date: d.from_date
};
}, function(error, rows) {
var i;
if (dateu.length > 0) {
for (i = 0; i < rows.length; i++) {
if (rows[i].date === dateu) {
lst.push(rows[i]);
console.log(rows[i]);
}
}
}
if (cityu.length > 0) {
for (i = 0; i < lst.city.length; i++) {
if (lst.city[i] === cityu) {
lst2.push(lst[i]);
console.log(lst2);
}
}
}
if (numberu.length > 0) {
for (i = 0; i < rows.length; i++) {
if (lst.number[i] === numberu) {
lst3.push(lst2[i]);
console.log(lst3);
}
}
}
});
};
One minor inconsequential change, moved the declaration of var i to the top of the function block, because technically you were declaring it three times, and jslint/jshint would complain - though nothing would break (yet)
I'm still not completely sure on your logic, but looking at Tiny Giant's gist, it seems like there are only three combinations:
1) Only dateu exists.
2) dateu and cityu exist.
3) dateu, cityu, and numberu exist.
So you don't care about the condition where dateu and numberu exist, but cityu is empty, right?
Okay, I reread your code. It seems like you have rows, and you have three possible filters. Filter rows based on AND, for example cityu AND dateu.
If so, here's a giant refactor. Just as a note, there may be some JavaScript errors because I had no way of testing this. But the code is fairly simple and straightforward:
var lst = [] // I'm not using these.
var lst2 = []
var lst3 = []
alert(cityu);
alert(dateu);
alert(numberu);
var getActiveFilters = function() {
// Edit possibleFilters as necessary.
// the key should reflect the header of the column
// and the value is a variable referring to the user-inputted string
var possibleFilters = {
'date': dateu,
'city': cityu,
'number': numberu
};
var activeFilters = {};
for (key in possibleFilters) {
if (possibleFilters[key].length > 0) {
activeFilters[key] = possibleFilters[key];
}
}
return activeFilters;
}
// just made this into a function to get it out of the callback
var functionAfterCsv = function(rows) {
var activeFilters = getActiveFilters();
var filteredList = [];
var addRow = false;
for(i = 0; i < rows.length; i++) {
// see if the current row matches all the filters present
for (key in activeFilters) {
if (rows[i][key] === activeFilters[key]) {
addRow = true;
} else {
addRow = false;
// if the row doesn't meet one of the conditions,
// there's no need to check the rest
break;
}
}
if (addRow) {
filteredList.push(row[i]);
}
}
return filteredList;
};
d3.csv("kyle.csv", function (d) {
return {
city: d.from,
number: d.phone_number,
date: d.from_date
};
}, function (error, rows) {
functionAfterCsv(rows);
})
});
If you're filtering using OR, then you'll need to change your comparison to something like this:
for (key in activeFilters) {
if (rows[i][key] === activeFilters[key]) {
addRow = true;
break; // if one is true, that's good enough for an OR
} else {
addRow = addRow || false;
}
}
if (addRow) {
filteredList.push(row[i]);
// reset addRow for the next row
addRow = false;
}
Hope this was closer to your intended logic!

Having trouble detecting undefined objects in an array

Quick bit about my background:
-been learning for about 3 months;
-work in tech support for a small software company. 2 years exp.
-a lot of knowledge is secondhand and I am still learning the basics
I am trying to create an object every second. The object is created directly to the last position of an array that remembers a set quantity of objects created before the most recent one
function Fruit(name, position) {
this.name = name;
this.position = position;
}
var showXMostRecentFruits = 20;
var fruitCounter = 0;
function generateName() {
var name = 'Experimental Fruit' + fruitCounter;
return name;
}
var fruitsArray = [];
function shiftFruits() {
for (i = 0; i < showXMostRecentFruits; i++) {
fruitsArray[i] = fruitsArray[i + 1];
}
function updateFruitPositions() {
for (i = 0; i < showXMostRecentFruits; i++) {
fruitsArray[i].position = i;
}
}
var fruitTimer; //used for setting and clearing setTimeout
function createNewFruit() {
shiftFruits();
fruitsArray[showXMostRecentFruits - 1] = new Fruit(generateName());
updateFruitPositions();
fruitCounter += 1;
fruitTimer = setTimeout(function() {
createNewFruit();
}, 1000);
}
Say the function createNewFruit() is run once
createNewFruit();
Then I try to pull some meaning from the array
console.log(fruitsArray[19];
All I get is:
Fruit {}
undefined
This issue is when I want to run a loop (see updateFruitPositions()) that updates a propery of each object in the array, an error is returned that the objects are undefined. I get that they are undefined because they are not assigned to unique variables (at least not that I'm aware of). How can I identify the objects or how can I create unique containers for them so I access them in the array?
You need to test whether a given element is set to something before attempting to write to one of its properties.
Instead of this...
for (i = 0; i < showXMostRecentFruits; i++) {
fruitsArray[i].position = i;
}
Use this:
for (i = 0; i < showXMostRecentFruits; i++) {
if (fruitsArray[i])
fruitsArray[i].position = i;
}
You fill the array from the end, staring with element 20. Without the if (fruitsArray[i]), you're attempting to set undefined.position = i for the first 19 elements.
You could replace the showFruits function with something much more efficient:
function shiftFruits() {
if (fruitsArray.length > showXMostRecentFruits) {
fruitsArray.shift();
}
}
and updateFruitPositions only needs to update members that exist, the length is controlled by shiftFruits:
function updateFruitPositions() {
for (i = 0; i < fruitsArray.length; i++) {
fruitsArray[i].position = i;
}
}
or where forEach is supported:
function updateFruitPositions() {
fruitsArray.forEach(function(fruit, i){fruit.position = i});
}
so it only visits members that exist. And the createNewFruit has:
fruitsArray.push(new Fruit(generateName());

How to pick a random property from an object without repeating after multiple calls?

I'm trying to pick a random film from an object containing film objects. I need to be able to call the function repeatedly getting distinct results until every film has been used.
I have this function, but it doesn't work because the outer function returns with nothing even if the inner function calls itself because the result is not unique.
var watchedFilms = [];
$scope.watchedFilms = watchedFilms;
var getRandomFilm = function(movies) {
var moviesLength = Object.keys(movies).length;
function doPick() {
var pick = pickRandomProperty(movies);
var distinct = true;
for (var i = 0;i < watchedFilms.length; i += 1) {
if (watchedFilms[i]===pick.title) {
distinct = false;
if (watchedFilms.length === moviesLength) {
watchedFilms = [];
}
}
}
if (distinct === true) {
watchedFilms.push(pick.title);
return pick;
}
if (distinct === false) {
console.log(pick.title+' has already been picked');
doPick();
}
};
return doPick();
}
T.J. Crowder already gave a great answer, however I wanted to show an alternative way of solving the problem using OO.
You could create an object that wraps over an array and makes sure that a random unused item is returned everytime. The version I created is cyclic, which means that it infinitely loops over the collection, but if you want to stop the cycle, you can just track how many movies were chosen and stop once you reached the total number of movies.
function CyclicRandomIterator(list) {
this.list = list;
this.usedIndexes = {};
this.displayedCount = 0;
}
CyclicRandomIterator.prototype.next = function () {
var len = this.list.length,
usedIndexes = this.usedIndexes,
lastBatchIndex = this.lastBatchIndex,
denyLastBatchIndex = this.displayedCount !== len - 1,
index;
if (this.displayedCount === len) {
lastBatchIndex = this.lastBatchIndex = this.lastIndex;
usedIndexes = this.usedIndexes = {};
this.displayedCount = 0;
}
do index = Math.floor(Math.random() * len);
while (usedIndexes[index] || (lastBatchIndex === index && denyLastBatchIndex));
this.displayedCount++;
usedIndexes[this.lastIndex = index] = true;
return this.list[index];
};
Then you can simply do something like:
var randomMovies = new CyclicRandomIterator(Object.keys(movies));
var randomMovie = movies[randomMovies.next()];
Note that the advantage of my implementation if you are cycling through items is that the same item will never be returned twice in a row, even at the beginning of a new cycle.
Update: You've said you can modify the film objects, so that simplifies things:
var getRandomFilm = function(movies) {
var keys = Object.keys(movies);
var keyCount = keys.length;
var candidate;
var counter = keyCount * 2;
// Try a random pick
while (--counter) {
candidate = movies[keys[Math.floor(Math.random() * keyCount)]];
if (!candidate.watched) {
candidate.watched = true;
return candidate;
}
}
// We've done two full count loops and not found one, find the
// *first* one we haven't watched, or of course return null if
// they've all been watched
for (counter = 0; counter < keyCount; ++counter) {
candidate = movies[keys[counter]];
if (!candidate.watched) {
candidate.watched = true;
return candidate;
}
}
return null;
}
This has the advantage that it doesn't matter if you call it with the same movies object or not.
Note the safety valve. Basically, as the number of watched films approaches the total number of films, our odds of picking a candidate at random get smaller. So if we've failed to do that after looping for twice as many iterations as there are films, we give up and just pick the first, if any.
Original (which doesn't modify film objects)
If you can't modify the film objects, you do still need the watchedFilms array, but it's fairly simple:
var watchedFilms = [];
$scope.watchedFilms = watchedFilms;
var getRandomFilm = function(movies) {
var keys = Object.keys(movies);
var keyCount = keys.length;
var candidate;
if (watchedFilms.length >= keyCount) {
return null;
}
while (true) {
candidate = movies[keys[Math.floor(Math.random() * keyCount)]];
if (watchedFilms.indexOf(candidate) === -1) {
watchedFilms.push(candidate);
return candidate;
}
}
}
Note that like your code, this assumes getRandomFilm is called with the same movies object each time.

Categories