I'm trying this:
props: ["gameState"],
computed: {
cards() {
return this.gameState.playerCards
},
rows() {
let cards = this.cards();
let max = 6;
if (cards.length <= max)
return [cards]
var mid = Math.ceil(cards.length / 2);
let return_value = [cards.slice(0, mid), cards.slice(mid)]
return return_value
}
}
but it tells me that this.cards is not a function. I was looking at Is it possible to use the computed properties to compute another properties in Vue? which said this should be the way to use other computed properties.
This is what I was explaining in comments.
computed: {
cards() {
return this.gameState.playerCards
},
rows() {
let cards = this.cards;
// if cards is ever undefined (maybe its populated asynchronously),
// cards.length will blow up. So, check here and return a sane
// value when it's undefined
if (!cards) return []
let max = 6;
if (cards.length <= max)
return [cards]
var mid = Math.ceil(cards.length / 2);
let return_value = [cards.slice(0, mid), cards.slice(mid)]
return return_value
}
}
Related
I'm trying to identify if a value is a Perfect Square and if that's the case, I want to push it into an array. I know that there is a built-in function that allows for it but I want to create an algorithm that does it. :)
Input: num = 16
Output: [4]
Example 2:
Input: num = 25
Output: [5]
Example 2:
Input: num = 14
Output: []
var isPerfectSquare = function(value) {
var perfectSquareVal = []
var highestValue = value;
var lowestValue = 0;
while (lowestValue < highestValue) {
var midpoint = 1 + Math.floor((highestValue + lowestValue)/2);
if (midpoint * midpoint === value) {
perfectSquareVal.push(midpoint);
} else if (midpoint * midpoint > value) {
highestValue = midpoint;
} else if (midpoint * midpoint < value) {
lowestValue = midpoint;
}
}
console.log(perfectSquareVal);
};
isPerfectSquare(16);
That seems really complicated to check if a number is a square, you could simply check if the square root is an Integer:
var isPerfectSquare = function(value) {
return Number.isInteger(Math.sqrt(value));
}
And if the function returns true, then push to array.
You could change the algorithm a bit by
taking the arthmetic mean with a flored value,
return if the product is found (why an array for the result?),
check only the greater oroduct because the smaller one is included in the check for equalness,
use decremented/incremented values, becaus the actual value is wrong,
keep a pure function, take ouput to the outside.
var isPerfectSquare = function (value) {
var highestValue = value,
lowestValue = 0;
while (lowestValue < highestValue) {
let midpoint = Math.floor((highestValue + lowestValue) / 2),
product = midpoint * midpoint;
if (product === value) return midpoint;
if (product > value) highestValue = midpoint - 1;
else lowestValue = midpoint + 1;
}
};
console.log(isPerfectSquare(25));
console.log(isPerfectSquare(250));
This is my data : https://api.myjson.com/bins/pmzf0
I retrieve all the leaf nodes of that data by using this function :
function getLeafNodes(nodes, result = []) {
for (var i = 0, length = nodes.length; i < length; i++) {
if (!nodes[i].children) {
result.push(nodes[i]);
} else {
result = getLeafNodes(nodes[i].children, result);
}
}
return result;
}
This is the returned result :https://api.myjson.com/bins/12qiq4
Then I calculated the percentage info of each element by getting its max value then multiplying it by 1.2 to obtain my target Value.
var maxVal = Math.max.apply(Math, leafs.map(function (o) { return o.value; }))
var targetVal = maxVal * 1.2;
Then I obtain my array of percentages for each element by using the following code :
var percentageData = leafs.map(function (o) {
return { percentage: (o.value / targetVal * 100).toFixed(2) };
})
This returns an array of percentage data : https://api.myjson.com/bins/mnte4
Now how do I insert this back into my original data ?
Or is my approach wrong and I can straight away calculate the percentage info for each element in my original data without all this steps.
Instead of saving the percentage values in a separate array like,
var percentageData = leafs.map(function (o) {
return { percentage: (o.value / targetVal * 100).toFixed(2) };
})
You can add a new percentage field to leafs using foreach like,
leafs.forEach(function (o) {
o['percentage'] = (o.value / targetVal * 100).toFixed(2);
})
I have range function and output functions they works correct,now I want create sum function for using as callbac function in range function,but when some function executed local variable let us say total or sum initialize 0(zero),how can solve this problem?
function range(start,end,callback,step) {
// body...
step=step || 1;
for(i=start;i<=end;i=i+step){
callback(i);
}
}
function output(a) {
// body...
console.log(a);
}
function sum(m){
var total=0;
// some code
}
range(1,5,output);
range(1,5,sum);
function range(start,end,callback,step) {
// body...
var aggregate;
step=step || 1;
for(i=start;i<=end;i=i+step){
aggregate = callback(i, aggregate);
}
}
function output(a) {
// body...
console.log(a);
}
function sum(m, aggregate){
return m + aggregate;
}
range(1,5,output);
range(1,5,sum);
This way you could even do cool stuff like
function conc(m, aggregate) {
return aggregate + m.toString();
}
range(1,5,conc,2); //prints 135
Continuition style code, like you've started it with range(), can get really weird and cumbersome.
And please, please, mind defining your local variables. like i
function range(start,end,callback,step) {
step=step || 1;
for(var i=start; i<=end; i=i+step)
callback(i);
}
function output(...label) {
return function(...args){
console.log(...label, ...args);
}
}
function sum(callback){
var total = 0;
return function(value){
//will log ever intermediate total, because sum() has no way to tell when the sequence is over.
callback(total += +value || 0);
}
}
range(1,5,output('range:'));
range(1,5,sum(output('sum:')));
In this case, I'd prefer using a generator instead, although the higher order functions get obsolete.
function *range(start,end,step) {
step = +step || (end < start? -1: 1);
for(var value = start, count = (end - start) / step; count-- >= 0; value += step)
yield value
}
function sum(iterator){
var total = 0, v;
for(v of iterator) total += +v || 0;
return total;
}
console.log("range:", ...range(1,5))
console.log("sum of range:", sum(range(1,5)))
//just to show that this works with your regular array as well
console.log("sum of array:", sum([1,2,3,4,5]));
//and some candy, as requested by Bergi ;)
//I like to stay with the interfaces as close as possible to the native ones
//in this case Array#reduce
var fold = (iterator, callback, start = undefined) => {
var initialized = start !== undefined,
acc = start,
index = 0,
value;
for(value of iterator){
acc = initialized?
callback(acc, value, index):
(initialized=true, value);
++index;
}
if(!initialized){
throw new TypeError("fold of empty sequence with no initial value");
}
return acc;
}
//and the ability to compose utility-functions
fold.map = (callback, start = undefined) => iterator => fold(iterator, callback, start);
console.log(" ");
var add = (a,b) => a + b; //a little helper
console.log('using fold:', fold(range(1,5), add, 0));
//a composed utility-function
var sum2 = fold.map(add, 0);
console.log('sum2:', sum2( range(1,5) ));
Clearly a range function should not take a callback but be a generator function in modern JavaScript, however you were asking how to write such a callback.
You've already tagged your questions with closures, and they are indeed the way to go here. By initialising a new total within each call of the outer function, you don't need to worry about how to reset a global counter.
function makeSum() {
var total=0;
return function(m) {
total += m;
return total; // so that we can access the result
}
}
var sum = makeSum();
range(1, 5, sum);
output(sum(0));
Won't simply calling the callback on the range array suffice if the callback is not undefined? Like this:
> function range(n, callback) {
const r = [...Array(n).keys()]
if (callback) {
return callback(r)
}
return r
}
> function sum(arr) {
return arr.reduce((a, b) => a + b, 0)
}
> range(10)
> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
> range(10, sum)
> 45
After searching for quite some time, I still haven't found what I'm looking for.
There's a fair amount of examples that either require creating a new instance, or only have functions that don't return anything (which means the problem can be solved with returning this).
I hope the following example illustrates my point well:
// Say I have these functions
function aNumber(){
var max = 100, min = 0;
return (Math.floor(Math.random() * (max - min + 1)) + min);
}
function divideBy(_number, _divider){
return (_number / _divider);
}
function multiplyBy(_number, _multi){
return (_number * _multi);
}
function add(_number, _add){
return (_number + _add);
}
function subtract(_number, _sub){
return (_number - _sub);
}
// #########################################################
// I can do this with them
var test = aNumber();
test = divideBy(aNumber, 2);
test = add(aNumber, 5);
test = multiplyBy(aNumber, 3);
test = subtract(aNumber, 10);
// I would like to do this however:
var test = aNumber().divideBy(2).add(5).multiplyBy(3).subtract(10);
What would be the most efficient way to make the last line work?
Am I misinformed that this is possible without creating a new instance of something?
Yes, this requires changing the Prototype of an Object. Objects are instances. So you need to create an object to do this kind of thing.
function MyNum(value) {
this._val = value; // Having _variable is for denoting it is a private variable.
}
Initialize objects using:
var myNum = new MyNum(5);
And now using this, define these:
MyNum.prototype.divideBy = function () {}
MyNum.prototype.multiplyBy = function () {}
Don't forget to use return this; inside these functions.
Try like below for creating without instance and prototype keyword.
One more method is been added here you can set number or random number by default. if the number not specified.
var Calculator = {
setNumber: function(givenNumber) {
var max = 100,
min = 0;
this.number = (givenNumber) ? givenNumber : (Math.floor(Math.random() * (max - min + 1)) + min);
return this;
},
divideBy: function(_divider) {
this.number = (this.number / _divider);
return this;
},
multiplyBy: function(_multi) {
this.number = (this.number * _multi);
return this;
},
add: function(_add) {
this.number = (this.number + _add);
return this;
},
subtract: function(_sub) {
this.number = (this.number - _sub);
return this;
},
result: function () {
return this.number;
}
}
document.write('<pre>');
document.writeln(Calculator.setNumber(2).divideBy(2).add(5).multiplyBy(3).subtract(10).result());
document.writeln(Calculator.setNumber(4).divideBy(2).add(5).multiplyBy(3).subtract(10).number);
document.writeln(Calculator.setNumber().divideBy(2).add(5).multiplyBy(3).subtract(10).result());
document.write('</pre>');
Yes, you do need to create an instance of something. This can be a simple object literal, function constructor, etc...
The idea is that all of your methods are stored on some object, right? The only way to access those methods is to access them through that object. With this in mind, each function must RETURN the object that holds all of these methods.
A quick example
var myMethods = {
one: function() {
console.log('one');
// You can return 'this' or reference the object by name
return this;
// or
// return myMethods;
},
two: function() {
console.log('two');
return this;
}
};
myMethods.one().two().one().two();
//=> 'one', 'two', 'one', 'two'
Watch out when you reference the method directly, like so
var someMethod = myMethods.one;
someMethod() //=> undefined
This is because 'this' is now referencing the global object, which is another story for another day. Just watch out if you reference a method in this way.
Although it is generally not recommended to add functions to the prototype of JavaScript primitives, you can do what you are looking for by doing so.
function aNumber(){
var max = 100, min = 0;
return (Math.floor(Math.random() * (max - min + 1)) + min);
}
function divideBy(_number, _divider){
return (_number / _divider);
}
function multiplyBy(_number, _multi){
return (_number * _multi);
}
function add(_number, _add){
return (_number + _add);
}
function subtract(_number, _sub){
return (_number - _sub);
}
Number.prototype.divideBy = function(_divider){
return divideBy(this, _divider);
};
Number.prototype.multiplyBy = function(_multi){
return multiplyBy(this, _multi);
};
Number.prototype.add = function(_add){
return add(this, _add);
};
Number.prototype.subtract = function(_sub){
return subtract(this, _sub);
};
var test = aNumber().divideBy(2).add(5).multiplyBy(3).subtract(10);
Just like Praveen and Venkatraman said, I found the following posts about chaining, but there all have to declare a new instanse before accessing any methods for changing
method-chaining-in-javascript and beautiful-javascript-easily-create-chainable-cascading-methods-for-expressiveness
or you can use this implementation https://jsfiddle.net/ayinloya/zkys5dk6/
function aNumber() {
var max = 100;
var min = 0;
this._number = (Math.floor(Math.random() * (max - min + 1)) + min);
console.log("a init", this._number)
}
aNumber.prototype.divideBy = function(_divider) {
this._number = (this._number / _divider)
return this;
}
aNumber.prototype.multiplyBy = function(_multi) {
this._number = (this._number * _multi);
return this;
}
aNumber.prototype.add = function(_add) {
this._number = (this._number + _add);
return this;
}
aNumber.prototype.subtract = function(_sub) {
this._number = (this._number - _sub);
return this;
}
aNumber.prototype.ans = function() {
return this._number;
}
var a = new aNumber()
alert(a.add(2).subtract(1).ans())
If you don't want to pull in a library and want to have functions that are reusable (and not bind to a specific class, e.g. a Calculator). What you can do is to wrap the input into an array and then pass it through a series of map functions. In the end just take the first element and you will have your result.
function aNumber(){
var max = 100, min = 0;
return (Math.floor(Math.random() * (max - min + 1)) + min);
}
function divideBy(_number, _divider){
return (_number / _divider);
}
function multiplyBy(_number, _multi){
return (_number * _multi);
}
function add(_number, _add){
return (_number + _add);
}
function subtract(_number, _sub){
return (_number - _sub);
}
// #########################################################
var result = [aNumber()]
.map(item => divideBy(item, 2))
.map(item => add(item, 5))
.map(item => multiplyBy(item, 3))
.map(item => subtract(item, 10))
[0];
console.log(result);
This probably is not the most efficient way but usually speed is "good enough".
I wrote a function that takes the number (amount) of songs, the object of songs and makes a new object, which includes new amount of songs chosen randomly.
The problem is that when I start it with number of 3, for example, it works correctly, but then I start this function with less number and it shows me the previous result with 3 songs instead of 2. If then I start it with number 5 I want to see 5 new song, but instead I get my previous 3 songs and 2 new. Why It doesn't choose randomly again?
$scope.getRandom = function(max) {
return Math.floor(Math.random() * (max + 1));
};
$scope.chooseSongs = function(hide) {
if (hide) {
$scope.hideDiv();
}
if ($scope.number > songs.length) {
$scope.number = songs.length;
}
while ($scope.newSongs.length < $scope.number) {
$scope.rand = $scope.getRandom(songs.length - 1);
$scope.songName = songs[$scope.rand].name;
if ($scope.newSongs.indexOf($scope.songName) == -1) {
$scope.newSongs.push($scope.songName);
}
}
$scope.number = 1;
};
When you use .push on an array, it does what it says: it "pushes" the new data in the back of the array, ignoring the fact if there already is data or not.
So you never clear your array, and keep "pushing" new data to the back.
An easy solution for this is adding $scope.newSongs = [] $scope.newSongs.length = 0; at the start of your function:
$scope.getRandom = function(max) {
return Math.floor(Math.random() * (max + 1));
};
$scope.chooseSongs = function(hide) {
$scope.newSongs.length = 0; //$scope.newSongs = [];
if (hide) {
$scope.hideDiv();
}
if ($scope.number > songs.length) {
$scope.number = songs.length;
}
while ($scope.newSongs.length < $scope.number) {
$scope.rand = $scope.getRandom(songs.length - 1);
$scope.songName = songs[$scope.rand].name;
if ($scope.newSongs.indexOf($scope.songName) == -1) {
$scope.newSongs.push($scope.songName);
}
}
$scope.number = 1;
};
Edit: Updated after an interesting comment from Deblaton Jean-Philippe. If you just reassign $scope.newSongs, AngularJs won't automatically update the view, if you instead clear the length, it will.