I keep getting this question wrong. Counting Bits using javascript - javascript

This is the question.
Given an integer n, return an array ans of length n + 1 such that for each i (0 <= i <= n), ans[i] is the number of 1's in the binary representation of i.
https://leetcode.com/problems/counting-bits/
And this is my solution below.
If the input is 2, expected output should be [0,1,1] but I keep getting [0,2,2]. Why is that???
var countBits = function(n) {
//n=3. [0,1,2,3]
var arr=[0];
for (var i=1; i<=n; i++){
var sum = 0;
var value = i;
while(value != 0){
sum += value%2;
value /= 2;
}
arr.push(sum);
}
return arr;
};
console.log(countBits(3));

You're doing way too much work.
Suppose b is the largest power of 2 corresponding to the first bit in i. Evidently, i has exactly one more 1 in its binary representation than does i - b. But since you're generating the counts in order, you've already worked out how many 1s there are in i - b.
The only trick is how to figure out what b is. And to do that, we use another iterative technique: as you list numbers, b changes exactly at the moment that i becomes twice the previous value of b:
const countBits = function(n) {
let arr = [0], bit = 1;
for (let i = 1; i <= n; i++){
if (i == bit + bit) bit += bit;
arr.push(arr[i - bit] + 1);
}
return arr;
};
console.log(countBits(20));
This technique is usually called "dynamic programming". In essence, it takes a recursive definition and computes it bottom-up: instead of starting at the desired argument and recursing down to the base case, it starts at the base and then computes each intermediate value which will be needed until it reaches the target. In this case, all intermediate values are needed, saving us from having to think about how to compute only the minimum number of intermediate values necessary.

Think of it this way: if you know how many ones are there in a number X, then you immediately know how many ones are there in X*2 (the same) and X*2+1 (one more). Since you're processing numbers in order, you can just push both derived counts to the result and skip to the next number:
let b = [0, 1]
for (let i = 1; i <= N / 2; i++) {
b.push(b[i])
b.push(b[i] + 1)
}
Since we push two numbers at once, the result will be one-off for even N, you have to pop the last number afterwards.

use floor():
sum += Math.floor(value%2);
value = Math.floor(value/2);
I guess your algorithm works for some typed language where integers division results in integers

Here's a very different approach, using the opposite of a fold (such as Array.prototype.reduce) typically called unfold. In this case, we start with a seed array, perform some operation on it to yield the next value, and recur, until we decide to stop.
We write a generic unfold and then use it with a callback which accepts the entire array we've found so far plus next and done callbacks, and then chooses whether to stop (if we've reached our limit) or continue. In either case, it calls one of the two callbacks.
It looks like this:
const _unfold = (fn, init) =>
fn (init, (x) => _unfold (fn, [...init, x]), () => init)
// Number of 1's in the binary representation of each integer in [`0 ... n`]
const oneBits = (n) => _unfold (
(xs, next, done) => xs .length < n ? next (xs .length % 2 + xs [xs .length >> 1]) : done(),
[0]
)
console .log (oneBits (20))
I have a GitHub Gist which shows a few more examples of this pattern.
An interesting possible extension would be to encapsulate the handling of the array-to--length-n bit, and make this function trivial. That's no the only use of such an _unfold, but it's probably a common one. It could look like this:
const _unfold = (fn, init) =>
fn (init, (x) => _unfold (fn, [...init, x]), () => init)
const unfoldN = (fn, init) => (n) => _unfold (
(xs, next, done) => xs .length < n ? next (fn (xs)) : done (),
init
)
const oneBits = unfoldN (
(xs) => xs .length % 2 + xs [xs .length >> 1],
[0]
)
console .log (oneBits (20))
Here we have two helper functions that make oneBits quite trivial to write. And those helpers have many potential uses.

Related

Ramda.js transducers: average the resulting array of numbers

I'm currently learning about transducers with Ramda.js. (So fun, yay! 🎉)
I found this question that describes how to first filter an array and then sum up the values in it using a transducer.
I want to do something similar, but different. I have an array of objects that have a timestamp and I want to average out the timestamps. Something like this:
const createCheckin = ({
timestamp = Date.now(), // default is now
startStation = 'foo',
endStation = 'bar'
} = {}) => ({timestamp, startStation, endStation});
const checkins = [
createCheckin(),
createCheckin({ startStation: 'baz' }),
createCheckin({ timestamp: Date.now() + 100 }), // offset of 100
];
const filterCheckins = R.filter(({ startStation }) => startStation === 'foo');
const mapTimestamps = R.map(({ timestamp }) => timestamp);
const transducer = R.compose(
filterCheckins,
mapTimestamps,
);
const average = R.converge(R.divide, [R.sum, R.length]);
R.transduce(transducer, average, 0, checkins);
// Should return something like Date.now() + 50, giving the 100 offset at the top.
Of course average as it stands above can't work because the transform function works like a reduce.
I found out that I can do it in a step after the transducer.
const timestamps = R.transduce(transducer, R.flip(R.append), [], checkins);
average(timestamps);
However, I think there must be a way to do this with the iterator function (second argument of the transducer). How could you achieve this? Or maybe average has to be part of the transducer (using compose)?
As a first step, you can create a simple type to allow averages to be combined. This requires keeping a running tally of the sum and number of items being averaged.
const Avg = (sum, count) => ({ sum, count })
// creates a new `Avg` from a given value, initilised with a count of 1
Avg.of = n => Avg(n, 1)
// takes two `Avg` types and combines them together
Avg.append = (avg1, avg2) =>
Avg(avg1.sum + avg2.sum, avg1.count + avg2.count)
With this, we can turn our attention to creating the transformer that will combine the average values.
First, a simple helper function that allow values to be converted to our Avg type and also wraps a reduce function to default to the first value it receives rather than requiring an initial value to be provided (a nice initial value doesn't exist for averages, so we'll just use the first of the values instead)
const mapReduce1 = (map, reduce) =>
(acc, n) => acc == null ? map(n) : reduce(acc, map(n))
The transformer then just needs to combine the Avg values and then pull resulting average out of the result. n.b. The result needs to guard for null values in the case where the transformer is run over an empty list.
const avgXf = {
'##transducer/step': mapReduce1(Avg.of, Avg.append),
'##transducer/result': result =>
result == null ? null : result.sum / result.count
}
You can then pass this as the accumulator function to transduce, which should produce the resulting average value.
transduce(transducer, avgXf, null, checkins)
I'm afraid this strikes me as quite confused.
I think of transducers as a way of combining the steps of a composed function on sequences of values so that you can iterate the sequence only once.
average makes no sense here. To take an average you need the whole collection.
So you can transduce the filtering and mapping of the values. But you will absolutely need to then do the averaging separately. Note that filter then map is a common enough pattern that there are plenty of filterMap functions around. Ramda doesn't have one, but this would do fine:
const filterMap = (f, m) => (xs) =>
xs .flatMap (x => f (x) ? [m (x)] : [])
which would then be used like this:
filterMap (
propEq ('startStation', 'foo'),
prop ('timestamp')
) (checkins)
But for more complex sequences of transformations, transducers can certainly fit the bill.
I would also suggest that when you can, you should use lift instead of converge. It's a more standard FP function, and works on a more abstract data type. Here const average = lift (divide) (sum, length) would work fine.

Assigning values whilst creating a 2D array

Here is some Javascript code that creates a 2-dimension array and fills each cell with a random number.
// populate 2D array with integers
const row = 5, col = 7
let pic = new Array(row).fill(0).map(item => (new Array(col).fill(0)))
for (let x = 0; x < row; x++) {
for (let y = 0; y < col; y++) {
pic[x][y] = Math.floor((Math.random() * 90) + 10)
}
}
console.log(JSON.stringify(pic))
I'm looking for a more 'elegant' solution. My questions:
Is there a way to use the fill so that I can put in my target values? Then I can be finished with creating the array in one line.
How do I use a double .map to populate the 2D array, instead of a double for loop?
Is there a way to assign the output from the map / for loops directly into a variable? Then I don't need a separate create statement.
What is the best way to reshape an array? For example, changing a 1-by-10 array into a 5-by-2 array.
Is there a way to enforce a type? For instance the first dimension is a string, 2nd is an integer, etc.
Feel free to add your own definition of elegance. One of the things I'm looking for is a flexible approach that can also work with 3D arrays.
You could take a nested Array.from with a length and a mapping function.
const
fn = () => Math.floor(Math.random() * 5),
row = 5,
col = 7,
array = Array.from({ length: row }, () => Array.from({ length: col }, fn));
array.forEach(a => console.log(...a));
Is there a way to use the fill so that I can put in my target values? Then I can be finished with creating the array in one line.
No, fill is not that flexible. There is Array.from(iterable, callback) but I find it cumbersome and it is slow. I'd rather write that utility quickly
function array(n, callback){
const output = Array(n);
for(let i=0; i<n; ++i) output[i] = callback(i);
return output;
}
How do I use a double .map to populate the 2D array, instead of a double for loop?
map creates a new Array, by calling the callback function for each item on the current Array. You can abuse it to mutate the Array that is iterating. You can ignore the returnes Array and abuse it as forEach; but then map simply is the wrong tool.
var newMatrix = Array(5).fill().map(() => Array(7).fill().map(() => Math.random()));
the fill part is necessary, because Array(length) creates a sparse Array of that length and map only iterated defined indices (even if they contain undefined)
Is there a way to assign the output from the map / for loops directly into a variable? Then I don't need a separate create statement.
I'm not sure what you mean, because you already do that here let pic = new Array(row).fill(0).map(...)
What is the best way to reshape an array? For example, changing a 1-by-10 array into a 5-by-2 array.
function array(n, callback) {
const output = Array(n);
for (let i = 0; i < n; ++i) output[i] = callback(i);
return output;
}
function toGroupsOf(n, data) {
return array(Math.ceil(data.length / n), i => data.slice(n * i, n * (i + 1)));
}
const oneByTen = [array(10, v => v)];
console.log(oneByTen);
const twoByFive = toGroupsOf(5, oneByTen.slice().flat());
console.log(twoByFive);
Is there a way to enforce a type? For instance the first dimension is a string, 2nd is an integer, etc.
No, not in JS. btw. everything but the last dimension will be Arrays, not String.
But check out Typescript.
Feel free to add your own definition of elegance. One of the things I'm looking for is a flexible approach that can also work with 3D arrays.
// a general purpose function to create n-dimensional arrays.
// m(...dimensions, (...indices) => value)
function m(...args) {
return args.reduceRight((cb, length) => (...indices) => {
const output = Array(length);
for (let i = 0; i < length; ++i)
output[i] = cb(...indices, i);
return output;
})();
}
let data = m(5,7, () => Math.floor(Math.random() * 90 + 10));
console.log(data);
// 4-dimensions
console.log(m(2,3,4,5, Math.random));
// a 5x5 identity-matrix
console.log(m(5,5, (i,j) => i === j? 1: 0).join("\n"));
I'm a user of strongly typed languages like Scala, where for instance, you could never store a string in an integer variable. I find the laissez faire of Javascript difficult.
I have mixed opinions on that. I loved the way that static types and compile-time errors found little mistakes/oversights back when I learned (in AS3). Nowadays and with Typescript I often find Typescript to be too opinionated and find myself thinking f off compiler, I know/mean what I'm writing here and prefer the flexibility of JS. On the other hand, I still enjoy the assistance that comes from the IDE knowing what Objects I'm currently dealing with and what properties/methods they provide.
Heavily inspired by: https://stackoverflow.com/a/53859978/9758920
const row = 5, col = 7;
let pic = [...Array(row)].map(r => [...Array(col)].map(c => ~~(Math.random()*90)+10));
console.log(pic)
This should work.
const randomNumber = Math.floor((Math.random()*90)+10);
const randomMatrix = (row, col) => {
return new Array(row).fill(randomNumber).map(item => (new Array(col).fill(randomNumber)))
}
console.log(randomMatrix(5, 7))
Try the snippet below. initializeArray accepts parameters for width, height and a value for each cell.
const initialize2DArray = (w, h, val = null) =>
Array.from({ length: h }).map(() => Array.from({ length: w }).fill(val));
console.log(initialize2DArray(3, 3, 0)) // 3x3 matrix filled with zeros
If you prefer a N-dimension array, try the snippet below:
const initializeNDArray = (val, ...args) =>
args.length === 0
? val
: Array.from({ length: args[0] }).map(() => initializeNDArray(val, ...args.slice(1)));
console.log(initializeNDArray(-1, 3, 3, 3))

Same code runs differently on different devices

I'm new to coding, still learning. My friend gave me a task to write a function that does return the 2nd highest number from an array, I've managed to do it using array.prototype.sort(). He said to replace "-" with a "<" or ">" to make the code more clear, that's where the problem started.
I'm using VCS on windows, and it's not working properly.
My friend uses a mac, everything works fine.
Tried it on jsfiddle, everything works fine.
const secondMax = (arr) => {
return arr.sort((a, b) => b - a)[1]; //does return the correct number after console.log()
};
const secondMax = (arr) => {
return arr.sort((a, b) => a < b)[1]; //does not
};
"a < b" should be sorting descending
"a > b" should be sorting ascending
But no matter which operator I use, the sorting fails and just returns the second number from the array
You're supposed to return a number, not a boolean. So the first is correct. The latter might work by chance on some javascript engines, but it's not guaranteed to.
sort sorts the array as String by default. If you pass a comparator, then it's a function which will depend on two parameters and return:
negative, if the first parameter is smaller than the second
0 if they are equal
positive, if the first parameter is greater than the second
Using a logical operator instead of the above is mistaken.
However, if you are interested in finding the second largest number, then it's better to do it using a cycle:
var largestNumbers = [];
var firstIndex = (arr[0] < arr[1]) ? 1 : 0;
largestNumbers.push(arr[firstIndex]);
largestNumbers.push(arr[1 - firstIndex]);
for (var i = 2; i < arr.length; i++) {
if (largestNumbers[1] < arr[i]) {
if (largestNumbers[0] < arr[i]) {
largestNumbers[1] = largestNumbers[0];
largestNumbers[0] = arr[i];
}
}
}
This is quicker than sorting an array and more importantly, it does not destroy your initial order just to find the second largest number.

Functional composition in JavaScript

I know this is quite possible since my Haskell friends seem to be able to do this kind of thing in their sleep, but I can't wrap my head around more complicated functional composition in JS.
Say, for example, you have these three functions:
const round = v => Math.round(v);
const clamp = v => v < 1.3 ? 1.3 : v;
const getScore = (iteration, factor) =>
iteration < 2 ? 1 :
iteration === 2 ? 6 :
(getScore(iteration - 1, factor) * factor);
In this case, say iteration should be an integer, so we would want to apply round() to that argument. And imagine that factor must be at least 1.3, so we would want to apply clamp() to that argument.
If we break getScore into two functions, this seems easier to compose:
const getScore = iteration => factor =>
iteration < 2 ? 1 :
iteration === 2 ? 6 :
(getScore(iteration - 1)(factor) * factor);
The code to do this probably looks something like this:
const getRoundedClampedScore = compose(round, clamp, getScore);
But what does the compose function look like? And how is getRoundedClampedScore invoked? Or is this horribly wrong?
The compose function should probably take the core function to be composed first, using rest parameters to put the other functions into an array, and then return a function that calls the ith function in the array with the ith argument:
const round = v => Math.round(v);
const clamp = v => v < 1.3 ? 1.3 : v;
const getScore = iteration => factor =>
iteration < 2 ? 1 :
iteration === 2 ? 6 :
(getScore(iteration - 1)(factor) * factor);
const compose = (fn, ...transformArgsFns) => (...args) => {
const newArgs = transformArgsFns.map((tranformArgFn, i) => tranformArgFn(args[i]));
return fn(...newArgs);
}
const getRoundedClampedScore = compose(getScore, round, clamp);
console.log(getRoundedClampedScore(1)(5))
console.log(getRoundedClampedScore(3.3)(5))
console.log(getRoundedClampedScore(3.3)(1))
Haskell programmers can often simplify expressions similar to how you'd simplify mathematical expressions. I will show you how to do so in this answer. First, let's look at the building blocks of your expression:
round :: Number -> Number
clamp :: Number -> Number
getScore :: Number -> Number -> Number
By composing these three functions we want to create the following function:
getRoundedClampedScore :: Number -> Number -> Number
getRoundedClampedScore iteration factor = getScore (round iteration) (clamp factor)
We can simplify this expression as follows:
getRoundedClampedScore iteration factor = getScore (round iteration) (clamp factor)
getRoundedClampedScore iteration = getScore (round iteration) . clamp
getRoundedClampedScore iteration = (getScore . round) iteration . clamp
getRoundedClampedScore iteration = (. clamp) ((getScore . round) iteration)
getRoundedClampedScore = (. clamp) . (getScore . round)
getRoundedClampedScore = (. clamp) . getScore . round
If you want to convert this directly into JavaScript then you could do so using reverse function composition:
const pipe = f => g => x => g(f(x));
const compose2 = (f, g, h) => pipe(g)(pipe(f)(pipe(h)));
const getRoundedClampedScore = compose2(getScore, round, clamp);
// You'd call it as follows:
getRoundedClampedScore(iteration)(factor);
That being said, the best solution would be to simply define it in pointful form:
const compose2 = (f, g, h) => x => y => f(g(x))(h(y));
const getRoundedClampedScore = compose2(getScore, round, clamp);
Pointfree style is often useful but sometimes pointless.
I think part of the trouble you're having is that compose isn't actually the function you're looking for, but rather something else. compose feeds a value through a series of functions, whereas you're looking to pre-process a series of arguments, and then feed those processed arguments into a final function.
Ramda has a utility function that's perfect for this, called converge. What converge does is produce a function that applies a series of functions to a series of arguments on a 1-to-1 correspondence, and then feeds all of those transformed arguments into another function. In your case, using it would look like this:
var saferGetScore = R.converge(getScore, [round, clamp]);
If you don't want to get involved in a whole 3rd party library just to use this converge function, you can easily define your with a single line of code. It looks a lot like what CaptainPerformance is using in their answer, but with one fewer ... (and you definitely shouldn't name it compose, because that's an entirely different concept):
const converge = (f, fs) => (...args) => f(...args.map((a, i) => fs[i](a)));
const saferGetScore = converge(getScore, [round, clamp]);
const score = saferGetScore(2.5, 0.3);

How to deterministically combine ints in a way that it always generates unique values?

I have a set of randomly generated ints, and an evolve(set) function that takes a set, removes two ints and inserts 4 new ints. I want the set never to have repeated ints. That is, no matter how many times I apply evolve(evolve(...evolve(set))), it should never have duplicated values.
What is a simple choice of combine(int x, int y) -> int that guarantees that property with high probability?
Example:
// Helpers.
var range = length => Array.from({length}, i => i);
var random = () => (Math.random() * Math.pow(2,31) | 0);
var removeRandom = set => set.splice(random() % set.length, 1)[0];
var hasRepeated = set => !set.sort((a,b) => a - b).reduce((a,b) => a && a !== b && b || 0, -1);
// Receives two parent ints, returns 4 derived ints.
// Can't use random() here; it must generate 4 ints
// from simple functions (multiplication, bitwise
// operations, etc.) of `a` and `b`.
function combine(a, b) {
return [a + b + 0, a + b + 1, a + b + 2, a + b + 3];
};
// Removes two ints from set, inserts 4 ints.
function evolve(set) {
var a = removeRandom(set);
var b = removeRandom(set);
set.push(...combine(a,b));
};
// Random initial set of ints.
var set = range(64).map(random);
// No matter how many times `evolve` is applied,
// the set should never have repeated ints.
for (var i = 0; i < 50000; ++i) {
evolve(set);
}
// Prints `true` if algorithm is correct
// (no repeated number was generated).
console.log(!hasRepeated(set));
Notice that, here, combine(a,b) just adds them together. This is a bad choice; with as few as 50000 calls to evolve, it already fails the test. I could use a linear congruential generator, but I wonder if it can be simpler than that under those conditions. Perhaps some use of XOR?
If you have the space to keep an array with the universe of possible entries, you can just randomize it, then keep track of the indices that bound your set, incrementing the starting index to remove elements and the ending index to add them.
You can either randomize the whole array up front, or as the ending index gets incremented.

Categories