Running a function a specified number of times - javascript

var nTimes = function (n, func) {
var numberOfTimesRan = 0;
var resultOfRunningFunc;
return function() {
if (numberOfTimesRan < n) {
resultOfRunningFunc = func.apply(null, arguments);
numberOfTimesRan++;
return resultOfRunningFunc;
}
return resultOfRunningFunc;
}
return resultOfRunningFunc;
}
var column = function(board) {
var counter = 0;
var checker = {};
for (var i = 0; i < board.length; i++) {
var key = board[i][counter];
checker[key] = '';
}
counter++;
if (Object.keys(checker).length !== 9) {
return "Try again!";
}
}
nTimes(9, column);
var result2 = column([[5, 3, 4, 6, 7, 8, 9, 1, 2],
[6, 7, 2, 1, 9, 0, 3, 4, 9],
[1, 0, 0, 3, 4, 2, 5, 6, 0],
[8, 5, 9, 7, 6, 1, 0, 2, 0],
[4, 2, 6, 8, 5, 3, 7, 9, 1],
[7, 1, 3, 9, 2, 4, 8, 5, 6],
[9, 0, 1, 5, 3, 7, 2, 1, 4],
[2, 8, 7, 4, 1, 9, 6, 3, 5],
[3, 0, 0, 4, 8, 1, 1, 7, 9]]) //, "Try again!")
console.log(result2)
Im new to JavaScript and im trying to practice closures. What I want is to run the column function 9 times. Currently in the nTimes function func is getting called on column and the right argument is getting passed in but nTimes is only getting ran once. Any advice on how i can fix it to get it to keep running?

You can use the function nTimes as used below to run a function multiple times.
function nTimes(count, func) {
for (x=0;count>=x;x++) {
func;
}
}
function testFunc(msg) {
console.log(msg)
}
nTimes(9, testFunc("Hello World!"));
This is a simpler version to the one you were trying to use. Your function did not work once you use return the code instantly exits out of the function, meaning the code below it fill not work.

function nTimes(count, func) {
for (x=0;count>=x;x++) {
func;
}
}
function testFunc(msg) {
console.log(msg)
}
nTimes(9, testFunc("Hello World!"));
I tried this code, but it logs "Hello world" only once for me, I changed it for this implemantaion and it works for me.
function nTimes(count, func) {
for (x=0;count>=x;x++) {
func();
}
}
function testFunc(msg) {
console.log(msg)
}
nTimes(9, testFunc.bind(null, "Hello World!"));

Related

Spot start and end index of values outside specified bounds?

I have 3 arrays of size n :
let values = [5, 5, 5, 6, 7, 6, 5, 4, 3, 3, 4, 5, 5];
let min_arr = [3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3];
let max_arr = [7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7];
let n = values.length;
I am trying to spot the indexes of the start and end of the "zones" where min_arr[i] > values[i] or max_arr[i] < values[i].
In the previous arrays the first zone : values[4] = 7 > 6 = max_arr[4] and !(values[5] = 6 > 6 = max_arr[5]) thus start = 4 and end = 5.
In the previous arrays the second zone : values[8] = 3 < 4 = min_arr[8] and values[9] = 3 < 4 = min_arr[9] but !(values[10] = 4 < 3 = min_arr[10]) thus start = 8 and end = 10.
In the previous arrays the expected output would be : [[4, 5], [8, 10]].
Nb: It does not matter if the last end index is greater than n.
Here is my code so far :
let temp = values
.map((e, i) => min_arr[i] > e || max_arr[i] < e ? i : undefined)
.filter((e) => e);
console.log(temp);
Output
[4, 8, 9]
My logic here is to first get all the indexes where the value is not in the bounds before removing consecutive values and adding the end value.
let res = [];
let start = temp[0];
for (let i = 0; i < temp.length; i++) {
if (i + 1 == temp.length) {
res.push([start, temp[i] + 1]);
break;
}
if (temp[i] + 1 != temp[i + 1]) {
res.push([start, temp[i] + 1]);
start = temp[i + 1];
}
}
console.log(res);
Output
[[4, 5], [8, 10]]
As a beginner in JavaScript, I find this method crude and I believe that the whole process can be done in a declarative way. How should I proceed ?
Please don't hesitate to edit this question if it lacks clarity.
Here are not so crude methods, probably they are in declarative way, also with handling some corner-cases. Corner cases i mean in result you are expencting arrays with 2 elements, open index and close index. So if the last element in array is out of bound - still an array with 2 elements will be returned. And at this point im curious about the correct output, probably you have to clarify it a bit. I assumed that indexes shoult be "first index of item that is out of bounds" and "last index of item that is out of bounds", not the "last index + 1"
let values = [5, 5, 5, 6, 7, 6, 5, 4, 3, 3, 4, 5, 5];
let min_arr = [3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3];
let max_arr = [7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7];
function getZones(values, predicateFn) {
const reduced = values.reduce(
(acc, curr, i) => {
const isMet = predicateFn(curr, i);
if (isMet) {
if (acc._zone) acc._zone[1] = i;
else acc._zone = [i];
} else if (acc._zone) {
// -1 due to current index is ok, previous was not.
acc._zone[1] = i - 1;
acc.result.push(acc._zone);
acc._zone = undefined;
}
return acc;
},
{
_zone: undefined,
result: []
}
);
// Case when zone was opened and not closed.
// Happens for last item only.
const { _zone, result } = reduced;
if (_zone) {
if (_zone.length === 1) {
_zone[1] = _zone[0];
}
result.push(_zone);
}
return result;
}
const res = getZones(values, (curr, i) => curr < min_arr[i] || curr > max_arr[i]);
console.log(JSON.stringify(res));
Test set i checked with:
const testSets = [
{
// Original set
values: [5, 5, 5, 6, 7, 6, 5, 4, 3, 3, 4, 5, 5],
min_arr: [3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3],
max_arr: [7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7]
// [[4,4],[8,9]]
},
{
// with starting and ending outs
values: [2, 5, 5, 6, 7, 6, 5, 4, 3, 3, 4, 5, 10],
min_arr: [3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3],
max_arr: [7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7]
// [[0,0],[4,4],[8,9],[12,12]]
},
{
// with starting and ending "wave"
values: [2, 8, 2, 6, 7, 6, 5, 4, 3, 3, 4, 2, 2, 10],
min_arr: [3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3],
max_arr: [7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7]
// [[0,2],[4,4],[8,9],[11,13]]
},
{
// Completely out of bounds
values: [2, 2, 2, 2, 2, 2, 2, 8, 8, 8, 8, 8, 8, 8],
min_arr: [3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3],
max_arr: [7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7]
// [[0,13]]
}
];
Also, here is a codesandbox so you can check the correct output and behavior.
Your method will work only for 2 consecutive values , try an example with more consecutive values like [[2, 7], [8, 11]] and check your method .
The solution can be the next:
let values = [5, 5, 5, 6, 7, 6, 5, 4, 3, 3, 4, 5, 5];
let min_arr = [3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3];
let max_arr = [7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7];
const result = values
.map((num, i) => (min_arr[i] > num || max_arr[i] < num ? i : undefined))
.reduce((previousValue, currentValue, currentIndex, array) => {
if ((currentValue || currentValue === 0) && !array[currentIndex - 1]) {
const findNextSibling = array.slice(currentIndex).findIndex(i => !i);
const finalConsecutiveValue =
findNextSibling === -1 || findNextSibling === 0
? 1
: findNextSibling + currentIndex;
previousValue.push([currentValue, finalConsecutiveValue]);
}
return previousValue;
}, []);
console.log('result', result);

JavaScript: Change all repeated values to 0 in array

I have an array with duplicate values
let ary = [5, 1, 3, 5, 7, 8, 9, 9, 2, 1, 6, 4, 3];
I want to set the repeated values to 0:
[0, 0, 0, 0, 7, 8, 0, 0, 2, 0, 6, 4, 0]
can find out the repeated value, but I want to change the repeated value to 0, is there any better way?
let ary = [5, 1, 3, 5, 7, 8, 9, 9, 2, 1, 6, 4, 3];
Array.prototype.duplicate = function () {
let tmp = [];
this.concat().sort().sort(function (a, b) {
if (a == b && tmp.indexOf(a) === -1) tmp.push(a);
});
return tmp;
}
console.log(ary.duplicate()); // [ 1, 3, 5, 9 ]
// ? ary = [0, 0, 0, 0, 7, 8, 0, 0, 2, 0, 6, 4, 0];
You could use indexOf() and lastIndexOf() method to solve your problem.
const array = [5, 1, 3, 5, 7, 8, 9, 9, 2, 1, 6, 4, 3];
const ret = array.map((x) =>
array.indexOf(x) !== array.lastIndexOf(x) ? 0 : x
);
console.log(ret);
const ary = [5, 1, 3, 5, 7, 8, 9, 9, 2, 1, 6, 4, 3];
// get set of duplicates
let duplicates = ary.filter((elem, index, arr) => arr.indexOf(elem) !== index)
duplicates = new Set(duplicates);
// set duplicate elements to 0
const res = ary.map(e => duplicates.has(e) ? 0 : e);
console.log(...res);
First, count values and store them in an object. Then loop over the array and check from that stored object whether the count of specific value is greater than 1 or not, if greater than 1, set that to 0. Here is the working example:
let ary = [5, 1, 3, 5, 7, 8, 9, 9, 2, 1, 6, 4, 3];
let countValue = {}, len = ary.length;
for (i = 0; i < len; i++) {
if (countValue[ary[i]]) {
countValue[ary[i]] += 1;
} else {
countValue[ary[i]] = 1;
}
}
for (i = 0; i < len; i++) {
if (countValue[ary[i]] > 1) {
ary[i] = 0;
}
}
console.log(...ary);
Probably this is the quickest algorithm, though it will alter your original array.
const array = [5, 1, 3, 5, 7, 8, 9, 9, 2, 1, 6, 4, 3];
const map = {};
for (let ind = 0; ind < array.length; ind++) {
const e = array[ind];
if (map[e] === undefined) {
map[e] = ind;
} else {
array[map[e]] = 0;
array[ind] = 0;
}
}
console.log(...array);

How object hash works to remove duplicates in this scenario?

function distinctUnion(arr, arr2) {
let merged = [...arr, ...arr2];
var result = [];
var map = {}
for (let i = 0; i < merged.length; i++) {
if (!map.hasOwnProperty(merged[i])) {
map[merged[i]] = true; // Line 3 --> if I remove this line, it prints duplicates
console.log('map', JSON.stringify(map, 2, null));
result.push(merged[i]);
}
}
return result;
}
let arr = [3, 4, 5, 6, 6, 4, 5, 8, 9, 10, 10];
let arr2 = [11, 11, 11, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6];
console.log('unique ', JSON.stringify(distinctUnion(arr, arr2), 2, null));
All we are setting here is map[merged[i]] = true; for all keys in object
map {"3":true,"4":true,"5":true,"6":true,"8":true,"9":true,"10":true,"11":true}
then how result.push(merged[i]) has only unique values?
I mean to say merged[i] inside loop should still have all array values including duplicates right?
I am not able to understand the link between map[merged[i]] = true; and result.push(merged[i])
If you do not set the property to anything, map.hasOwnProperty(...) will spuriously return false for the next time that value is encountered, thus allowing duplicates. You don't need to set it to true, as it is just used to indicate the presence of a key; any value is fineā€”even undefined!
function distinctUnion(arr, arr2) {
let merged = [...arr, ...arr2];
var result = [];
var map = {}
for (let i = 0; i < merged.length; i++) {
if (!map.hasOwnProperty(merged[i])) {
map[merged[i]] = undefined;
result.push(merged[i]);
}
}
return result;
}
let arr = [3, 4, 5, 6, 6, 4, 5, 8, 9, 10, 10];
let arr2 = [11, 11, 11, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6];
console.log('unique ', JSON.stringify(distinctUnion(arr, arr2), 2, null));
To make your code works, you just need to replace map[merged[i]] = true; with map[merged[i]] = undefined;.
However, you can make your function more simplified as follows:
function distinctUnion(arr, arr2) {
let map = {};
[...arr, ...arr2].forEach((x)=>{map[x] = x});
return Object.values(map);;
}
let arr = [3, 4, 5, 6, 6, 4, 5, 8, 9, 10, 10];
let arr2 = [11, 11, 11, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6];
console.log('Unique ', distinctUnion(arr, arr2));

Getting a "not defined" error in my JavaScript code when I think it is defined

I am working on a project for SkillCrush and am getting a "not defined" error, when I feel as though I've defined the variable at the top of the code. I 100% know I'm doing something wrong, but not sure what. Any suggestions?
var createPolitician = function (name)
{
var politician = {}; //is this not defined here?
politician.name = name;
politician.electionResults = null;
politician.totalVotes = 0;
return politician;
};
var oscar = createPolitician("Oscar Jiminez");
var luke = createPolitician("Luke Spencer");
oscar.electionResults = [5, 1, 7, 2, 33, 6, 4, 2, 1, 14, 8, 3, 1, 11, 11, 0, 5, 3, 3, 3, 7, 4, 8, 9, 3, 7, 2, 2, 4, 2, 8, 3, 15, 15, 2, 12, 0, 4, 13, 1, 3, 2, 8, 21, 3, 2, 11, 1, 3, 7, 2];
luke.electionResults = [4, 2, 4, 4, 22, 3, 3, 1, 2, 15, 8, 1, 3, 9, 0, 6, 1, 5, 5, 1, 3, 7, 8, 1, 3, 3, 1, 3, 2, 2, 6, 2, 14, 0, 1, 6, 7, 3, 7, 3, 6, 1, 3, 17, 3, 1, 2, 11, 2, 3, 1];
oscar.electionResults[9] = 1;
luke.electionResults[9] = 28;
oscar.electionResults[4] = 17;
luke.electionResults[4] = 38;
oscar.electionResults[43] = 11;
luke.electionResults[43] = 27;
console.log(oscar.electionResults);
console.log(luke.electionResults);
politician.countTotalVotes = function()
{
this.totalVotes = 0;
for (var i = 0; i < this.electionResults.length; i++);
{
this.totalVotes = this.totalVotes + this.electionResults[i];
}
}
oscar.countTotalVotes();
luke.countTotalVotes();
console.log(oscar.totalVotes);
console.log(luke.totalVotes);
Error:
"error"
"ReferenceError: politician is not defined
at reloyur.js:32:1"
politician.countTotalVotes = ...
That won't work as politician only exists while you create luke or oscar (it then points to one of them). Instead you could do:
luke.countTotalVotes = oscar.countTotalVotes = function() { /*...* };
But for more politicians that gets a bit complicated. You could however just make a function that you pass a politician into:
function countTotalVotes(politician) {
//...
}
countTotalVotes(luke);
Or you use the power of inheritance.
As I suggested in comments, you can rewrite Politician as a class, which basically gives you a template for reusable functionality. If you're not familiar with the concept, a good google term would be "prototypal inheritance" for follow-up on the subject in general. For now, here's a rewrite of your script using a class:
class Politician {
constructor (name) {
this.name = name;
this.electionResults = [];
}
// no need to even write a .countTotalVotes() method
// just define .totalVotes as a getter that does the work
get totalVotes () {
var total = 0;
for (var i = 0; i < this.electionResults.length; i++) {
total += this.electionResults[i];
}
return total;
}
}
var oscar = new Politician("Oscar Jiminez");
var luke = new Politician("Luke Spencer");
oscar.electionResults = [5, 1, 7, 2, 33, 6, 4, 2, 1, 14, 8, 3, 1, 11, 11, 0, 5, 3, 3, 3, 7, 4, 8, 9, 3, 7, 2, 2, 4, 2, 8, 3, 15, 15, 2, 12, 0, 4, 13, 1, 3, 2, 8, 21, 3, 2, 11, 1, 3, 7, 2];
luke.electionResults = [4, 2, 4, 4, 22, 3, 3, 1, 2, 15, 8, 1, 3, 9, 0, 6, 1, 5, 5, 1, 3, 7, 8, 1, 3, 3, 1, 3, 2, 2, 6, 2, 14, 0, 1, 6, 7, 3, 7, 3, 6, 1, 3, 17, 3, 1, 2, 11, 2, 3, 1];
oscar.electionResults[9] = 1;
luke.electionResults[9] = 28;
oscar.electionResults[4] = 17;
luke.electionResults[4] = 38;
oscar.electionResults[43] = 11;
luke.electionResults[43] = 27;
// console.log(oscar.electionResults);
// console.log(luke.electionResults);
// these are no longer required
// oscar.countTotalVotes();
// luke.countTotalVotes();
console.log(oscar.name, 'has', oscar.totalVotes, 'votes');
console.log(luke.name, 'has', luke.totalVotes, 'votes');
Move your countTotalVotes function into your create function:
var createPolitician = function (name)
{
var politician = {};
politician.name = name;
// set to an empty array so this is defined
politician.electionResults = [];
politician.totalVotes = 0;
// here politician exists, add a function to the object that you can call later
politician.countTotalVotes = function()
{
this.totalVotes = 0;
for (var i = 0; i < this.electionResults.length; i++)
{
this.totalVotes = this.totalVotes + this.electionResults[i];
}
}
return politician;
};
I corrected your mistakes in your code. You could change your code like follows:
function createPolitician(name)
{
var politician =
{
name: name,
electionResults: null,
totalVotes: 0,
countTotalVotes: function()
{
//this.totalVotes = 0; <- irrelevant because you use it only one time
for(var i = 0; i < this.electionResults.length; i++)//";" symbol on the end is your mistake too
{
this.totalVotes += this.electionResults[i];
}
}
};
return politician;
};
var oscar = createPolitician("Oscar Jiminez");
var luke = createPolitician("Luke Spencer");
oscar.electionResults = [5, 1, 7, 2, 33, 6, 4, 2, 1, 14, 8, 3, 1, 11, 11, 0, 5, 3, 3, 3, 7, 4, 8, 9, 3, 7, 2, 2, 4, 2, 8, 3, 15, 15, 2, 12, 0, 4, 13, 1, 3, 2, 8, 21, 3, 2, 11, 1, 3, 7, 2];
luke.electionResults = [4, 2, 4, 4, 22, 3, 3, 1, 2, 15, 8, 1, 3, 9, 0, 6, 1, 5, 5, 1, 3, 7, 8, 1, 3, 3, 1, 3, 2, 2, 6, 2, 14, 0, 1, 6, 7, 3, 7, 3, 6, 1, 3, 17, 3, 1, 2, 11, 2, 3, 1];
oscar.electionResults[9] = 1;
luke.electionResults[9] = 28;
oscar.electionResults[4] = 17;
luke.electionResults[4] = 38;
oscar.electionResults[43] = 11;
luke.electionResults[43] = 27;
console.log(oscar.electionResults);
console.log(luke.electionResults);
oscar.countTotalVotes();
luke.countTotalVotes();
console.log(oscar.name, 'has', oscar.totalVotes, 'votes');
console.log(luke.name, 'has', luke.totalVotes, 'votes');
The error message should be accompanied with a line and column number. In this case, the error is occurring on line 32:
politician.countTotalVotes = function()
In the definition of the createPolitician function, you declared a variable named politician. var creates a variable that lives within the function it was declared in. If it is not inside of a function, it creates a global variable.
You left the function the variable was declared in, and thus it isn't usable anymore.
If you think about it, it'd be very ambiguous if you could re-use that politician variable later on. What would it refer to?
If you want to be able to call countTotalVotes() on the politicians, then Patrick's comment about using a Class is a good approach to take. You could also assign the function to the politician object that you return from createPolitician - this would give each instance of the politician its own copy of the function.
It's all about variable scope. Declare the politician object variable outside of the createPolitician function for you to access out of the function. It cannot be accessed out of its scope that is why you get an undefined error.

How can I change the position of a particular item in an array?

I'm trying to change an item's index position in an array, but I cannot figure out a way.
{
"items": [
1,
3,
2
]
}
You can use splice to move an element in an array:
var arr = [
1,
3,
2
];
var oldIndex = 2,
newIndex = 1;
arr.splice(newIndex, 0, arr.splice(oldIndex, 1)[0]);
This makes [1, 2, 3]
The internal splice removes and returns the element, while the external one inserts it back.
Just for fun I defined a generic function able to move a slice, not just an element, and doing the computation of the index:
Object.defineProperty(Array.prototype, "move", {
value:function(oldIndex, newIndex, nbElements){
this.splice.apply(
this, [newIndex-nbElements*(newIndex>oldIndex), 0].concat(this.splice(oldIndex, nbElements))
);
}
});
var arr = [0, 1, 2, 7, 8, 3, 4, 5, 6, 9];
arr.move(5, 3, 4);
console.log('1:', arr) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
var arr = [0, 1, 2, 7, 8, 3, 4, 5, 6, 9];
arr.move(3, 9, 2);
console.log('2:', arr); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
var arr = [0, 1, 2, 4, 5, 3, 6, 7];
arr.move(5, 3, 1);
console.log('3:', arr); // [0, 1, 2, 3, 4, 5, 6, 7]
var arr = [0, 3, 1, 2, 4, 5, 6, 7];
arr.move(1, 4, 1);
console.log('3:', arr); // [0, 1, 2, 3, 4, 5, 6, 7]
JS Bin
If you want to sort them in Unicode order (where numbers become strings) you can use sort() function.
items.sort();
If you have your custom order, you need to provide a sort function to the sort function.
function compare(a, b) {
if (a is less than b by some ordering criterion) {
return -1;
}
if (a is greater than b by the ordering criterion) {
return 1;
}
// a must be equal to b
return 0;
}
and you use it like this:
items.sort(compare(a, b));

Categories