Javascript Encapsulation and Compound Assignment Operator - javascript

My aim to to create an object in Javascript where I can easily just go block.red = 128; or block.red += 5. Which could easily be done using this.red inside the object, but I want my object also be able to do which is stumping me is to ensure that the red value falls within the accepted range (i.e. not above 255 and not below 0).
I've had a bit of a look around, and one thing I thought might work was encapsulation. The problem being then is that I can't use the compound assignment operator. Obviously this isn't the end of the world, but I would like to know if there are any solutions that I haven't thought up.
function colours(r, g, b) {
_r = r;
_g = g;
_b = b;
this.red = red;
function red(value) {
if (value == undefined) {
return _r;
} else {
if (value < 0) {
_r = 0;
} else if (value > 255) {
_r = 255;
} else {
_r = value;
}
}
}
}
// tests
colours(240, 120, 60);
alert(red());
red(120);
alert(red());
red(360);
alert(red());
// works up to here
red() -= 30;
alert(red());
So do you have any ideas of how I can keep the compound assignment operator while still ensuring the red value stays within range?

You can use getters and setters as one way to achieve this.
// our constructor function
function Color(r, g, b) {
return {
get red() {
return r;
},
set red(value) {
// let's make sure we get a number here
if ( typeof value === 'number' && !isNaN(value) ) {
// check the range
if (value < 0) {
r = 0;
} else if (value > 255) {
r = 255;
} else {
r = value;
}
} else {
// this gets set if they don't pass a number
r = 255;
}
}
// other color methods here
};
}
// --------------------
var red = new Color(255, 0, 0);
alert(red.red); // 255
red.red -= 55; // assignment within range, success
alert(red.red); // 200
red.red -= 999; // assignment out of range, failure
alert(red.red); // 0
red.red += 999; // assignment out of range, failure
alert(red.red); // 255
jsFiddle example

Related

Reading 7BitEncodedInt in Javascript

I am reading a binary in javascript. I think this file was written in C# and the the way binaries handle the strings in C# is a little different than how it is handled in as mentioned in
https://learn.microsoft.com/en-us/dotnet/api/system.io.binaryreader.readstring?view=net-7.0
The thing is that I am not able to find any library which allows me to read C# style strings OR 7bitEncodedInt. Any suggestions on any code/package that allows me to do that?
Actually, I found an answer in one of the libraries and modified according to what a getString would look like:
private GetString(buffer) {
try {
let length = this.Read7BitEncodedInt(buffer);
if (length < 0) {
this.toastrService.error('Error');
}
if (length == 0) {
return '';
} else {
return buffer.getNextString(length);
}
}
catch (exception){
this.toastrService.error('Error')
}
}
private Read7BitEncodedInt(buffer) {
let count = 0, shift = 0, b = 0, i = 0;
try {
do {
if (shift === 5 * 7) {
this.toastrService.error('Error');
}
//Get a single byte
b = buffer.getNextBytes(1);
// tslint:disable-next-line:no-bitwise
//Update the value of the int based on the byte that it belongs to(shift value)
count |= (b & 0x7F) << shift;
shift += 7;
i++;
// tslint:disable-next-line:triple-equals no-bitwise
//Exit if byte is empty
} while ((b & 0x80) != 0);
}
catch (exception){
this.toastrService.error('Error message');
}

Binary Search for multiple items within a Range (Log time filter)

I have an Array of Log items, already sorted by their timestamp (number of milliseconds since 1970). Now I want to filter them by a specific time range, so I think of Binary Search, however this variant is different than all variants I knew before as I need to find a range within a range. Note that there may be none or multiple items at the value edges.
I came up with this to reduce one range requirement but still don't know how to get to the first/last edge items:
filterByTime(min: number, max: number): LogItem[] {
const items = this.items;
const len = items.length;
if (min === undefined && max === undefined) {
return items.slice(0, len - 1);
}
min = min || Number.MIN_VALUE;
max = max || Number.MAX_VALUE;
const fn = (a: LogItem) => {
if (a.time < min) {
return -1;
} else if (a.time > max) {
return 1;
} else {
return 0;
}
};
const lowerBound = this.binarySearchBound(fn, 0, len, true);
if (lowerBound == -1) { return []; }
const upperBound = this.binarySearchBound(fn, 0, len, false);
return items.slice(lowerBound, upperBound + 1);
}
binarySearchBound(compareFn: (a: LogItem) => number, left: number, right: number, isLowerBound: boolean): number {
const items = this.items;
if (items.length == 0) {
return -1;
}
if (isLowerBound && compareFn(items[0]) == 0) {
return 0;
} else if (!isLowerBound && compareFn(items[items.length - 1]) == 0) {
return items.length - 1;
}
while (left <= right) {
const mid = (left + right) / 2;
const item = this.items[mid];
const compare = compareFn(item);
if (compare < 0) {
left = mid + 1;
} else if (compare > 0) {
right = mid - 1;
} else {
// What to do now?
}
}
return -1;
}
Worst case scenario, I can just do a linear search from the edge since I can assume there are not that much items at the edge but surely there is a better way I didn't think of but then I may have to iterate through the whole result set if mid falls in the middle of the result set.
EDIT for adding a note: It's possible for min or max is undefined (and could be both, in which case I can just set an if and return the copy of the whole array). Is it better to just substitute it with MIN_VALUE and MAX_VALUE if they are undefined, or is there a better way to handle that case?
I would suggest the following:
Write two binary search functions, as the execution time is then not hampered by passing and checking the isLowerBound boolean.
Make the returned upperBound to mean the next index after the potential last index that belongs to the range. This corresponds with how arguments work with native functions like slice.
Don't use -1 as a special index. If coded well, an empty range will come out of the two binary searches any way and give an empty array as result
Make the compare function to work with 2 parameters, so you can actually search for either the min or the max value.
Yes, I would use MIN_VALUE and MAX_VALUE as defaults and not test for boundary cases. If boundary cases happen often, it might be worth to include those checks, but in general be aware that these checks will then be executed for every filter, which may bring down the average execution time.
Here is the suggested implementation with integer data (instead of objects) to keep it simple. In order to have it run in a snippet I also removed the type references:
function filterByTime(min=Number.MIN_VALUE, max=Number.MAX_VALUE) {
const fn = (a, b) => a - b; // simplified (should be a.time - b.time)
const lowerBound = this.binarySearchLowerBound(fn, 0, this.items.length, min);
const upperBound = this.binarySearchUpperBound(fn, lowerBound, this.items.length, max);
return this.items.slice(lowerBound, upperBound);
}
function binarySearchLowerBound(compareFn, left, right, target) {
while (left < right) {
const mid = (left + right) >> 1;
if (compareFn(this.items[mid], target) < 0) {
left = mid + 1;
} else { // Also when equal...
right = mid;
}
}
return left;
}
function binarySearchUpperBound(compareFn, left, right, target) {
while (left < right) {
const mid = (left + right) >> 1;
if (compareFn(this.items[mid], target) <= 0) { // Also when equal...
left = mid + 1;
} else {
right = mid;
}
}
return left;
}
// Demo with simplified data (instead of objects with time property)
this.items = [1, 2, 2, 2, 3, 4, 4, 5, 5, 5, 6, 7, 8, 8];
console.log(this.filterByTime(2, 4));
console.log(this.filterByTime(4, 5));
Combined the variants on this article, I merged first and last code into a single function:
filterByTime(items: LogItem[], min: number, max: number): LogItem[] {
const len = items.length;
if (len == 0) {
return [];
}
if (min === undefined && max === undefined) {
return items.slice(0, len - 1);
}
min = min || Number.MIN_VALUE;
max = max || Number.MAX_VALUE;
const fn = (a: LogItem) => {
if (a.time < min) {
return -1;
} else if (a.time > max) {
return 1;
} else {
return 0;
}
};
const lowerBound = this.binarySearchBound(fn, 0, len, true);
if (lowerBound == -1) { return []; }
const upperBound = this.binarySearchBound(fn, 0, len, false);
return items.slice(lowerBound, upperBound + 1);
}
binarySearchBound(compareFn: (a: LogItem) => number, left: number, right: number, isLowerBound: boolean): number {
const items = this.items;
if (items.length == 0) {
return -1;
}
if (isLowerBound && compareFn(items[0]) == 0) {
return 0;
} else if (!isLowerBound && compareFn(items[items.length - 1]) == 0) {
return items.length - 1;
}
let result = -1;
while (left <= right) {
const mid = (left + right) / 2;
const item = this.items[mid];
const compare = compareFn(item);
if (compare < 0) {
left = mid + 1;
} else if (compare > 0) {
right = mid - 1;
} else {
result = mid;
if (isLowerBound) {
right = mid - 1;
} else {
left = mid + 1;
}
}
}
return result;
}

How to count number of ways to parenthesize boolean expression string to evaluate to desired result

Straight out of CTCI, 8.14: Given a boolean expression consisting of the symbols 0 (false), 1 (true), & (AND), | (OR), and ^(XOR), and a desired boolean result value result, implement a function to count the number of ways of parenthesizing the expression such that it evaluates to result.
I'm attempting a brute force approach that calculates every single possible combo, if matches desired result, add it to an array(combos) and return that result length. It seems to work for most expressions, but not the 2nd example given. What do I seem to be missing?
function countEval(s, goalBool, combos = []) {
// on first call make s into array since theyre easier to work with
if (!(s instanceof Array)) {
// and turn 1s and 0s into their bool equivalent
s = s.split('').map((item) => {
if (item === '1') {
return true;
} else if (item === '0'){
return false;
} else {
return item;
}
});
}
if (s.length === 1 && s[0] === goalBool) {
combos.push(s[0]); // can be anything really
} else {
for (let i = 0; i < s.length - 2; i = i + 2) {
// splice out the next 3 items
const args = s.splice(i, 3);
// pass them to see what they evaluate too
const result = evalHelper(args[0], args[1], args[2]);
// splice that result back in s array
s.splice(i, 0, result);
// pass that array to recurse
countEval(s, goalBool, combos);
// remove said item that was just put in
s.splice(i, 1);
// and reset array for next iteration
s.splice(i, 0, ...args);
}
}
return combos.length;
}
function evalHelper(a, op, b) {
if (op === '|') {
return a || b;
} else if (op === '&') {
return a && b;
} else if (op === '^') {
return a !== b;
}
}
With the 2 examples given it works for the first one, but not the second...
console.log(countEval('1^0|0|1', false)); // 2, correct
console.log(countEval('0&0&0&1^1|0', true)); // 30, should be 10!?!?!
The Bug
Your program is not taking into account overlap.
Example
Consider your program when s = '1|1|1|1'.
In one of the depth-first search iterations, your algorithm will make the reduction s = (1|1)|1|1. Then in a deeper recursive level in the same search, your algorithm will make the reduction s = (1|1)|(1|1). Now s is fully reduced, so you increment the length of combos.
In a different depth-first search iteration, your algorithm will first make the reduction s = 1|1|(1|1). Then in a deeper recursive level in the same search, your algorithm will make the reduction s = (1|1)|(1|1). Now s is fully reduced, so you increment the length of combos.
Notice that for both cases, s was parenthesized the same way, thus your program does not take into account overlap.
A Better Solution
A lot of times, when a problem is asking the number of ways something can be done, this is usually a big indicator that dynamic programming could be a potential solution. The recurrence relation to this problem is a bit tricky.
We just need to pick a "principle" operator, then determine the number of ways the left and right side could evaluate to true or false. Then, based on the "principle" operator and the goal boolean, we can derive a formula for the number of ways the expression could evaluate to the goal boolean given that the operator we picked was the "principle" operator.
Code
function ways(expr, res, i, j, cache, spaces) {
if (i == j) {
return parseInt(expr[i]) == res ? 1 : 0;
} else if (!([i, j, res] in cache)) {
var ans = 0;
for (var k = i + 1; k < j; k += 2) {
var op = expr[k];
var leftTrue = ways(expr, 1, i, k - 1, cache);
var leftFalse = ways(expr, 0, i, k - 1, cache);
var rightTrue = ways(expr, 1, k + 1, j, cache);
var rightFalse = ways(expr, 0, k + 1, j, cache);
if (op == '|') {
if (res) {
ans += leftTrue * rightTrue + leftTrue * rightFalse + leftFalse * rightTrue;
} else {
ans += leftFalse * rightFalse;
}
} else if (op == '^') {
if (res) {
ans += leftTrue * rightFalse + leftFalse * rightTrue;
} else {
ans += leftTrue * rightTrue + leftFalse * rightFalse;
}
} else if (op == '&') {
if (res) {
ans += leftTrue * rightTrue;
} else {
ans += leftFalse * rightFalse + leftTrue * rightFalse + leftFalse * rightTrue;
}
}
}
cache[[i, j, res]] = ans;
}
return cache[[i, j, res]];
}
function countEval(expr, res) {
return ways(expr, res ? 1 : 0, 0, expr.length - 1, {});
}

What does ||| mean in JavaScript?

I've googled this and searched through the JavaScript documentation but I can't find any mention of this operator: a |ǀ| b
When I try the operator on its own I get an error but when I run the following code it runs perfectly fine:
var a, b = 0; tex = '\u0076\u0061r'
var players, score = 0, x, y, z = 1;
function f(s) {
var t = 0, r = 0;
var js = 'window';
while (t == r) {
if (t == 1) {
r = s.length;
return false;
} else {
t += 1;
} for (var i = 0; i < 20; i++) {
r = 20;i+=9000;eval(s); x = 50; y =+ 8;
z = -20; y = s;
}
if (r < 20) {
return t + 2;
}}
return true;
} while (f(tex + ' \u01C0='+'0') && score < 900) {
score = 9000.0001;}eval(y); a = 1; b += a;
x = 50;{y =+ 8;
}
// testing:
document.writeln(false |ǀ| false); // 0
document.writeln(false |ǀ| true); // 1
document.writeln(true |ǀ| false); // 1
document.writeln(true |ǀ| true); // 1
Changing the values of a and b would suggest it works like || but I just can't work out why it works with the previous code, but doesn't work on its own. Does anyone know whats going on here?
It's not an operator. It's the | operator, twice, with a "Latin letter 'Dental Click'" character in between. That character is valid in JavaScript identifiers. Thus the expression:
false |ǀ| false
(probably) means the same thing as
false | undefined | false
because there's no real variable called ǀ. (edit — Actually there probably is, otherwise you'd get a reference error.)
The | (bitwise-OR) operator treats its operands as numbers, and both false and undefined become 0.
That function f() is what's defining a window property called ǀ.

JSLint: how not to make THIS function within a loop

In my angular application, I am using a loop to find in an object the nearest value to a given number and return its key.
For example, I want the closest values to 0.5:
for (var j in nums) {
if (0.5 > nums[j]) var prev = nums[j];
else if (0.5 <= nums[j]) {
// If the current number is equal to 0.5, or immediately higher, stores that number
// and stops the for each() loop
var next = nums[j];
// Get the value
var percentage = (Math.abs(0.5 - prev) < Math.abs(next - 0.5)) ? prev : next;
// Get the key from the value
$scope.seventyfive = parseInt('0' + Object.keys(nums).filter(function(key) {return nums[key] === percentage;})[0], 10);
break;
}
}
JSLint is pointing out that I shouldn't make functions within a loop, so I am trying to avoid that with:
filterPct = function (nums, pct) {
return function () {
return nums[key] === pct;
};
}
and
for (var j in nums) {
if (0.5 > nums[j]) var prev = nums[j];
else if (0.5 <= nums[j]) {
// If the current number is equal to 0.5, or immediately higher, stores that number
// and stops the for each() loop
var next = nums[j];
// Get the value
var percentage = (Math.abs(0.5 - prev) < Math.abs(next - 0.5)) ? prev : next;
// Get the key from the value
$scope.seventyfive = parseInt('0' + Object.keys(nums).filter(filterPct(nums, percentage))[0], 10);
break;
}
}
But this is returning 0 instead of the right value. I am positive I am missing something obvious, but I obviously need another pair of eyes...
UPDATE: Thanks to the support I received, this is the error-proof version of the code above:
filterPct = function (nums, pct) {
return function (key) {
return nums[key] === pct;
};
};
// Store the value with 50% Confidence
for (i in nums) {
if (nums.hasOwnProperty(i)) {
if (0.5 > nums[i]) {
prev = nums[i];
} else if (0.5 <= nums[i]) {
// If the current number is equal to 0.5, or immediately higher, stores that number
// and stops the for each() loop
next = nums[i];
// Get the value
percentage = (Math.abs(0.5 - prev) < Math.abs(next - 0.5)) ? prev : next;
// Get the key from the value
$scope.fifty = parseInt('0' + Object.keys(nums).filter(filterPct(nums, percentage))[0], 10);
break;
}
}
}
filterPct = function (nums, pct) {
return function () {
return nums[key] === pct;
};
}
You forgot to define key (it should be the first argument of the inner function).

Categories