Simple histogram algorithm in Javascript - javascript

Im creating a histogram algorithm. Im following the solution offered here.
I want to simply count the number of times each value has occurred.
However I cant quite get the algorithm right. My code is:
var values = [2, 4, 6, 3, 3];
var val_max = 6;
var val_min = 2;
var num_bins = parseInt(val_max - val_min + 1);
console.log('num_bins is ', num_bins);
var bin_width = (val_max-val_min)/num_bins;
console.log('bin_width is ', bin_width);
var to_plot = [];
for (var i = 0; i < num_bins; i++) {
to_plot.push(0);
}
for (var x = 0; x < values.length; x++) {
var bin_idx = parseInt((values[x] - val_min) / bin_width);
to_plot[bin_idx] = to_plot[bin_idx] + 1;
}
console.log('to_plot is ', to_plot);
If you look at the console logs, you'll see:
to_plot is [1, 2, 1, 0, 0, NaN]
I want that last index to be "1". But the problem is for values close the the maximum value, bin_idx is out of range. How can I tweak this so that I would get the following results?
to_plot is [1, 2, 1, 0, 1]
The jsfiddle is here.

Here's what I would do:
const data = [2, 4, 6, 3, 3];
print(histogram(data, 1)); // [1, 2, 1, 0, 1]
print(histogram(data, 2)); // [3, 1, 1]
print(histogram(data, 3)); // [4, 1]
print(histogram(data, 4)); // [4, 1]
print(histogram(data, 5)); // [5]
function histogram(data, size) {
let min = Infinity;
let max = -Infinity;
for (const item of data) {
if (item < min) min = item;
else if (item > max) max = item;
}
const bins = Math.ceil((max - min + 1) / size);
const histogram = new Array(bins).fill(0);
for (const item of data) {
histogram[Math.floor((item - min) / size)]++;
}
return histogram;
}
function print(x) {
console.log(JSON.stringify(x));
}
This works for non-integer values too.

I think your bin_width is wrong. Try this calculation instead:
var bin_width = (val_max - val_min) / (num_bins - 1);
That makes the bin_width == 1 which lets the rest of your code work.

Since the number of bins is equal to the number of integers between val_min and val_max, the bin_width is 1, not 0.8 as currently being calculated. You're basically counting integers here. Use this loop to generate the histogram:
for (var x = 0; x < values.length; x++) {
to_plot[values[x] - val_min] ++;
}

Related

LeetCode 768: Constructing a variation on a solution for Max Chunks To Make Sorted

LeetCode's Max Chunks To Make Sorted II challenge is:
Given an array arr of integers (not necessarily distinct), we split
the array into some number of "chunks" (partitions), and individually
sort each chunk. After concatenating them, the result equals the
sorted array.
What is the most number of chunks we could have made?
Example:
Input: arr = [2, 1, 3, 4, 4]
Output: 4
Explanation:
We can split into two chunks, such as [2, 1], [3, 4, 4].
However, splitting into [2, 1], [3], [4], [4] is the highest number of chunks possible.
The algorithm underlying the following solution is (the algorithm and the solution were posted as a comment on the solution page by a user named #benevolent. Unfortunately, I can't link to its comment):
If the largest number from arr[0] to (including) arr[k] is less than or equal to the smallest
number from arr[k+1] to the end, then we can split into two valid
chunks.
To illustrate:
left right
[......max] [min......]
To know the minimum element from k to arr.length-1, we can just
precompute from right to left.
The solution:
function maxChunksToSorted(arr) {
var minRight = Array(arr.length).fill(Number.MAX_SAFE_INTEGER);
for (var i = arr.length-2; i >= 0; --i) {
minRight[i] = Math.min(minRight[i+1], arr[i+1]);
}
var maxLeft = Number.MIN_SAFE_INTEGER;
var ans = 0;
for (var i = 0; i < arr.length; ++i) {
maxLeft = Math.max(maxLeft, arr[i]);
if (maxLeft <= minRight[i]) {
ans += 1
}
}
return ans;
};
console.log("expects: 1", "got:", maxChunksToSorted([5, 4, 3, 2, 1]));
console.log("expects: 4", "got:", maxChunksToSorted([2, 1, 3, 4, 4]));
My question:
I was trying to make a "mirror image" of the above solution, by "flipping" every action (e.g, the use of min becomes max, <= becomes >, and so on).
My maxArr indeed mirrors minRight (e.g., for [2, 1, 3, 4, 4], my maxArr is [MIN_SAFE_INTEGER, 1, 3, 4, 4], while the original minRight is [1, 3, 4, 4, MAX_SAFE_INTEGER]), but it clearly doesn't work, and I can't put my finger on the reason for that.
What's my fundamental problem?
Let me stress that I'm not looking for some other working solution. I'd like to understand what went wrong with my mirror solution, if it's even possible to make this mirror, and if not - what's the fundamental reason for that.
function maxChunksToSorted(arr) {
var maxArr = Array(arr.length).fill(Number.MIN_SAFE_INTEGER);
for (var i = 1; i <= arr.length; ++i) {
maxArr[i] = Math.max(maxArr[i-1], arr[i]);
}
var minLeft = Number.MAX_SAFE_INTEGER;
var ans = 0;
for (var i = 0; i < arr.length; ++i) {
minLeft = Math.min(minLeft, arr[i]);
if (minLeft > maxArr[i]) {
ans += 1
}
}
return ans;
};
console.log("expects: 1", "got:", maxChunksToSorted([5, 4, 3, 2, 1]));
console.log("expects: 4", "got:", maxChunksToSorted([2, 1, 3, 4, 4]));
This should do the job:
function chunk(list){
let sortedList = list.slice();
sortedList.sort();
var beginIndex = -1; var biggestFound;
var foundFirst = false; var foundLast = false;
for(var i = 0; i < list.length; i++){
if(beginIndex == -1) {
if(list[i] == sortedList[i]) print(list[i]);
else {beginIndex = i; biggestFound = list[i];}
}
else{
if(list[i] == sortedList[beginIndex]) foundFirst = true;
if(list[i] > biggestFound) biggestFound = list[i];
if(biggestFound == sortedList[i]) foundLast = true;
if(foundFirst && foundLast){
print(list.slice(beginIndex, i - beginIndex + 1));
foundFirst = false; foundLast = false; beginIndex = -1;
}
}
}
}
chunk([2,1,3,4,4]);
As I commented, if a chunk starts at position i, it must contain the element that corresponds to the position i in the sorted array and if it ends in position j, it must contain the element in the index j of the sorted array.
When both of these conditions are satisfied, you close the chunk and start a new one.
The complexity is O(n lg(n)), where n is the size of the array.

Given an array write a function that returns all the possible triplets/sequences of that array? JavaScript

For example, given A = [1, 2, 1, 1], the function should return 3.
Creates only three different sequences: (1, 2, 1), (1, 1, 1) and (2, 1, 1). The correct answer for this example is 3.
Given A = [1, 2, 3, 4], the function should return 4. There are four
ways: (1, 2, 3), (1, 2, 4), (1, 3, 4) and (2, 3, 4).
Given A = [2, 2, 2, 2], the function should return 1. There is only
one way: (2, 2, 2).
Given A = [2, 2, 1, 2, 2], the function should return 4. There are
four ways: (1, 2, 2), (2, 1, 2), (2, 2, 1) and (2, 2, 2).
Given A = [1, 2], the function should return 0
Write an efficient algorithm for the following assumptions:
N is an integer within the range [0..100,000]; each element of array A
is an integer within the range [1..N].
Here is my Brute Force Solution below!
I was wondering if anybody out there has a better more optimized solution?
Detected time complexity of this solution:
O(N**3*log(N)) or O(N**4)
const theatreTickets = (array) => {
let combos = []
if(array.length < 2) {
combos.length = 0
}
for(let i = 0; i <= array.length; i++) {
for(let j = i + 1; j <= array.length - 1; j++) {
for(let k = j + 1; k <= array.length - 1; k++) {
combos.push([array[i], array[j], array[k]])
}
}
}
combos = Array.from(new Set(combos.map(JSON.stringify)), JSON.parse)
return combos.length
}
console.log(theatreTickets([1, 2, 1, 1])) // Should Be 3
Thank you!
I think you need to combine, algorithm of combination and unique. It will work. Sample is given below.
Source: Efficient algorithm to get the combinations of all items in object
function combine(items, numSubItems) {
var result = [];
var indexes = new Array(numSubItems);
for (var i = 0 ; i < numSubItems; i++) {
indexes[i] = i;
}
while (indexes[0] < (items.length - numSubItems + 1)) {
var v = [];
for (var i = 0 ; i < numSubItems; i++) {
v.push(items[indexes[i]]);
}
result.push(v);
indexes[numSubItems - 1]++;
var l = numSubItems - 1; // reference always is the last position at beginning
while ( (indexes[numSubItems - 1] >= items.length) && (indexes[0] < items.length - numSubItems + 1)) {
l--; // the last position is reached
indexes[l]++;
for (var i = l +1 ; i < numSubItems; i++) {
indexes[i] = indexes[l] + (i - l);
}
}
}
return result;
}
var combinations = combine([1,2,1,1], 3);
console.log([...new Set(combinations.map(x => x.join(",")))]);
combinations = combine([1,2,3,4], 3);
console.log([...new Set(combinations.map(x => x.join(",")))]);

Make average of values inside array to smooth graph line

I have an array which represents the points of a graph with different values like the following one:
var array = [5, 3, 4, 1, 2];
I would like to loop through it and create a new array where the new values are:
An average between the value preceding it and the one coming after it.
Placed among the existing ones.
This means that array[0] will remain at the same position, while the other values will be pushed of one position. The new array should look like this:
var newArray = [5, 4, 3, 3.5, 4, 2.5, 1, 1.5, 2];
Do you have an idea on how to achieve this? Thanks in advance to your replies!
var array = [5, 3, 4, 1, 2];
var newArr = [array[0]]; // start the array with the first from the original
array.reduce((a, b) => {
newArr.push((a + b) / 2, b);
return b;
});
console.log(newArr);
var array = [5, 3, 4, 1, 2];
var newArray = [];
newArray.push(array[0]);
for(var i=0; i < array.length-1; i++)
{
var first = array[i];
var second = array[i+1];
var avg = (first+second)/2;
newArray.push(avg);
newArray.push(second);
}
https://jsfiddle.net/5utkvge8/
You are going to want to loop through your original array, pushing each number to the new one, and if you are not on the final element, get the average of array[i] and array[i+1]
var array = [5, 3, 4, 1, 2];
var newArray = [];
for (var i = 0; i < array.length; i++)
{
newArray.push(array[i])
if (!isNaN(array[i+1]))
{
newArray.push((array[i] + array[i+1]) / 2)
}
}
or in a functional, no-side effects, way:
var array = [5, 3, 4, 1, 2];
var newArray = array.reduce((result, value, index, array) => result.concat(index > 0 && index < array.length ? [(array[index-1] + value)/2, value] : value), [])
In case you can modify the original array:
var array = [5, 3, 4, 1, 2],
len = array.length * 2 - 2;
for (var i = 1; i < len; i = i + 2) {
array.splice(i, null, (array[i-1] + array[i]) / 2);
}
console.log(array);
let createdArr = []
[5, 3, 4, 1, 2].forEach( (item,index,arr) => {
createdArr.push(item)
if( index !== 0 && index + 1 !== arr.length ){
createdArr.push( (item + arr[ index + 1]) / 2 )
}
} )

Return all possible combinations of numbers in an array whose sum is less than or equal to n

var a = [1,3,6,10,-1];
function combinations(array, n) {
}
combinations(a, 9) // should return...
[[1], [3], [6], [-1], [1,3], [1,6], [1,-1], [3,6], [3,-1], [6, -1], [10, -1], [1,3,-1], [3,6,-1], [1,6,-1], [1,3,6,-1]]
maybe i'm missing some correct answers but you get the idea. Really dying to know how to solve this!
I would say the problem here is to take the power set of an array, and filter it down to only the elements whose sum is greater than a certain number.
The power set of a set is the set of all subsets of that set. (Say that five times fast and you'll be a mathematician)
For example, the power set of [1] is [[], [1]] and the power set of [1, 2] is [[], [1], [2], [1, 2]].
First I would define a powerSet function like this:
var powerSet = function (arr) {
// the power set of [] is [[]]
if(arr.length === 0) {
return [[]];
}
// remove and remember the last element of the array
var lastElement = arr.pop();
// take the powerset of the rest of the array
var restPowerset = powerSet(arr);
// for each set in the power set of arr minus its last element,
// include that set in the powerset of arr both with and without
// the last element of arr
var powerset = [];
for(var i = 0; i < restPowerset.length; i++) {
var set = restPowerset[i];
// without last element
powerset.push(set);
// with last element
set = set.slice(); // create a new array that's a copy of set
set.push(lastElement);
powerset.push(set);
}
return powerset;
};
Then I would define a function that takes the power set of the array and only includes elements whose sum is less than or equal to some amount:
var subsetsLessThan = function (arr, number) {
// all subsets of arr
var powerset = powerSet(arr);
// subsets summing less than or equal to number
var subsets = [];
for(var i = 0; i < powerset.length; i++) {
var subset = powerset[i];
var sum = 0;
for(var j = 0; j < subset.length; j++) {
sum += subset[j];
}
if(sum <= number) {
subsets.push(subset);
}
}
return subsets;
};
This might not be fast on large arrays, but it works well for small ones.
It looks like it gives the right answer for console.log(subsetsLessThan([1,3,6,10,-1], 9));
edit: a little more about the power set function as implemented here
The only subset of [] is [], so the power set of [] is a set containing only []. That would be [[]].
The initial if statement in the powerSet function immediately returns [[]] if you pass in [].
var powerSet = function (arr) {
if(arr.length === 0) {
return [[]];
}
If you pass in a set with at least one element, the powerSet function begins by removing the last element. For example, if you call powerSet on [1, 2], the variable lastElement will be set to 2 and arr will be set to [1].
var lastElement = arr.pop();
Then the powerSet function recursively calls itself to get the power set of the "rest" of the list. If you had passed in [1, 2], then restPowerset is assigned to powerSet([1]) which is [[], [1]].
var restPowerset = powerSet(arr);
We define a variable that's going to hold the power set of what was passed in, here [1, 2]
var powerset = [];
We loop through every set in restPowerset.
for(var i = 0; i < restPowerset.length; i++) {
var set = restPowerset[i];
Any subset of [1] is also a subset of [1, 2] so we add it to the list. That is, [] and [1] are both subsets of [1, 2].
powerset.push(set);
If you add the element 2 to any subset of [1], that is also a subset of [1, 2], so we add it to the list. Both [2] and [1, 2] are subsets of [1, 2].
set = set.slice(); // copy the array
set.push(lastElement); // add the element
powerset.push(set);
That's all. At this point, the variable powerset is [[], [2], [1], [1, 2]]. Return it!
}
return powerset;
};
Brute force O(N*2N) solution, where N = a.length < 31.
This uses the index i as a bit field to filter the elements of a in each iteration into a sublist.
var a = [1,3,6,10,-1];
function combinations(array, n) {
var lists = [], M = 1<<array.length;
for( var i = 1 ; i < M ; ++i ) {
var sublist = array.filter(function(c,k){return i>>k & 1});
if( sublist.reduce(function(p,c){return p+c},0) <= n )
lists.push(sublist);
}
return lists;
}
console.log(JSON.stringify(combinations(a,9)));
[[1],[3],[1,3],[6],[1,6],[3,6],[-1],[1,-1],[3,-1],[1,3,-1],[6,-1],[1,6,-1],[3,6,-1],[1,3,6,-1],[10,-1]]
Similar to Matt's answer, but uses Array.filter() and Array.reduce() to pack a punch. The variable, mask is incremented from 1 to 32-1 in this example (because array length is 5 and count = 1 << 5, which is 32). The array is filtered for each mask increment, producing a new array or permutation where only certain values are included.
A value is included in the permutation if the mask shifted right by the value's index is odd. Think binary here, because either a value is supposed to be in the permutation or it isn't (0 or 1) and since the mask will go through all possible numbers, all of the possible permutations are covered directly in the number when expressed as binary:
index: 4,3,2,1,0
mask: 0 0 0 0 1 (grab index 0, [1])
mask: 0 0 0 1 0 (grab index 1, [3])
mask: 0 0 0 1 1 (grab index 0 and 1, [1,3])
mask: 1 1 0 0 0 (grab index 3 and 4, [10,-1])
var a = [1,3,6,10,-1];
function combinations(array, n) {
var mask, len = array.length, count = 1 << len, permutations = [];
var indexVisible = function(v, i) { return ((mask >> i) & 1) == 1 }
var sum = function(a, b) { return a + b }
for (mask = 1; mask < count; ++mask) {
permutations.push(array.filter(indexVisible))
}
return permutations.filter(function(p) { return p.reduce(sum) <= n })
}
console.log(JSON.stringify(combinations(a, 9)));
The function, indexVisible() is used to filter the original array and return a permutation that matches the mask.
The function, sum() is used to reduce each permutation to the sum of its values, and if that sum is less than or equal to n then it is included in the final result and returned from combinations()
Here are the permutations:
[[1],[3],[1,3],[6],[1,6],[3,6],[1,3,6],[10],[1,10],[3,10],[1,3,10],[6,10],[1,6,10],[3,6,10],[1,3,6,10],[-1],[1,-1],[3,-1],[1,3,-1],[6,-1],[1,6,-1],[3,6,-1],[1,3,6,-1],[10,-1],[1,10,-1],[3,10,-1],[1,3,10,-1],[6,10,-1],[1,6,10,-1],[3,6,10,-1],[1,3,6,10,-1]]
Here are the results:
[[1],[3],[1,3],[6],[1,6],[3,6],[-1],[1,-1],[3,-1],[1,3,-1],[6,-1],[1,6,-1],[3,6,-1],[1,3,6,-1],[10,-1]]
You can see how all of this works and play with different combinations in this JSFiddle.
The following code will give you all sub-arrays summing up to 9 or less..
function getSubArrays(arr,n){
var len = arr.length,
subs = Array(Math.pow(2,len)).fill();
return subs.map((_,i) => { var j = -1,
k = i,
res = [];
while (++j < len ) {
k & 1 && res.push(arr[j]);
k = k >> 1;
}
return res;
}).slice(1)
.filter(a => a.reduce((p,c) => p+c) <= n);
}
var arr = [1,3,6,10,-1],
result = getSubArrays(arr,9);
console.log(JSON.stringify(result));
edit: giving credit where due.. borrowed the bulk of this logic from this answer
var combinations = function(a,m) {
var gc = function(a) {
var fn = function(n, src, got, all) {
if (n == 0) {
if (got.length > 0) {
all[all.length] = got;
}
return;
}
for (var j = 0; j < src.length; j++) {
fn(n - 1, src.slice(j + 1), got.concat([src[j]]), all);
}
return;
}
var all = [];
for (var i = 0; i < a.length; i++) {
fn(i, a, [], all);
}
all.push(a);
return all;
}
var c = gc(a);
return c.filter(function(e) {
var n = e.length;
var sum = 0;
while(n--)
sum += parseFloat(e[n]) || 0;
return sum<=m;
},m);
}
var a = [1,3,6,10,-1];
combinations(a,9);
output
[[1], [3], [6], [-1], [1, 3], [1, 6], [1, -1], [3, 6], [3, -1], [6, -1], [10, -1], [1, 3, -1], [1, 6, -1], [3, 6, -1], [1, 3, 6, -1]]
It looked like to much fun not to play, here's what I have.
Javascript
function kCombs(set, k) {
var setLength = set.length,
combs = [],
i = 0,
tailLength,
head,
tail,
j,
t,
u;
if (k > 0 && k <= setLength) {
if (k === setLength) {
combs.push(set);
} else if (k === 1) {
while (i < setLength) {
combs.push([set[i]]);
i += 1;
}
} else {
u = k - 1;
setLength = setLength - k + 1;
while (i < setLength) {
t = i + 1;
head = set.slice(i, t);
tail = kCombs(set.slice(t), u);
j = 0;
tailLength = tail.length;
while (j < tailLength) {
combs.push(head.concat(tail[j]));
j += 1;
}
i = t;
}
}
}
return combs;
}
function combinations(array, n) {
var arrayLength = array.length,
combs = [],
combsLength,
results = [],
temp = 0,
current,
currentLength,
i,
j,
k = 1;
while (k <= arrayLength) {
i = 0;
current = kCombs(array, k);
currentLength = current.length;
while (i < currentLength) {
combs.push(current[i]);
i += 1;
}
k += 1;
}
i = 0;
combsLength = combs.length;
while (i < combsLength) {
j = 0;
current = combs[i];
currentLength = current.length;
while (j < currentLength) {
temp += current[j];
j += 1;
}
if (temp <= n) {
results.push(current);
}
temp = 0;
i += 1;
}
return results;
}
var a = [1, 3, 6, 10, -1];
console.log(JSON.stringify(combinations(a, 9)));
Output
[[1],[3],[6],[-1],[1,3],[1,6],[1,-1],[3,6],[3,-1],[6,-1],[10,-1],[1,3,-1],[1,6,-1],[3,6,-1],[1,3,6,-1]]
On jsFiddle
And a jsPerf of all these, although #jcarpenter solutions gives an ambiguity.
On a modern browser you could squeeze more out of this solution using for intead of while as they are highly optimised for for. And assign by index rather than push would also give you a performance boost.
It would be nice to extend the performance tests to include some more test sets, maybe if I get bored.
Brevity is very cryptic here. How about some descriptive functions?
The approach uses binary to create maps of all the possible combinations. Then the map is used to pluck items from the array. The plucked items are summed, and that's about it.
The result of combinations([1, 3, 6, 10, -1], 9) produced is: [[-1],[10,-1],[6],[6,-1],[3],[3,-1],[3,6],[3,6,-1],[1],[1,-1],[1,6],[1,6,-1],[1,3],[1,3,-1],[1,3,6,-1]].
Here is a Fiddle.
/**
* Get an array of all the possible combinations
* of x items. Combinations are represented as binary.
* #param {Number} x - example 2
* #return {String[]} - example ['00', '01', '10', '11']
*/
function getCombinationsOfXItems(x) {
var allOn = '',
numCombos = 0,
i = 0,
combos = [];
// find upper limit
while (allOn.length < x) {
allOn += 1;
}
// number of possible combinations
numCombos = parseInt(allOn, 2) + 1;
// generate the combos
while(i < numCombos) {
combos.push(pad(toBase2(i++), allOn.length));
}
return combos;
}
/**
* Pad a string with leading zeros.
* #param {String} x - example '100'
* #param {Number} length - example 6
* #return {String} - example '000100'
*/
function pad(x, length) {
while (x.length < length) {
x = 0 + x;
}
return x;
}
/**
* Get a number as a binary string.
* #param {Number} x - example 3
* #return {String} - example '11'
*/
function toBase2(x) {
return x.toString(2);
}
/**
* Given an array and a map of its items as a binary string,
* return the items identified by 1.
* #param {Array} arr - example [1,2,3]
* #param {String} binary - example '101'
* #return {Array} - example [1,3]
*/
function pluckFromArrayByBinary(arr, binary) {
var plucked = [],
i = 0,
max = binary.length;
for (; i < max; i++) {
if (binary[i] === '1') {
plucked.push(arr[i]);
}
}
return plucked;
}
/**
* Given an array, return a multi-dimensional
* array of all the combinations of its items.
* #param {Array} - example [1, 2];
* #return {Array[]} - [ [1], [1, 2], [2] ]
*/
function getCombosOfArrayItems(arr) {
var comboMaps = getCombinationsOfXItems(arr.length),
combos = [];
// remove the "all off" combo (ex: '00000')
comboMaps.shift();
for (var i = 0; i < comboMaps.length; i++) {
combos.push(pluckFromArrayByBinary(arr, comboMaps[i]));
}
return combos;
}
/**
* Return all possible combinations of numbers in an
* array whose sum is less than or equal to n
* #param {Number[]} arr
* #param {Number} x
* return {Number[]} - stringified for readability
*/
function combinations(arr, x) {
var combos = getCombosOfArrayItems(arr),
i = 0,
max = combos.length,
combo;
for (; i < max; i++) {
if (sumArray(combos[i]) > x) {
combos.splice(i, 1);
i--;
max--;
}
}
return JSON.stringify(combos);
}
/**
* Return the sum of an array of numbers.
* #param {Number[]} arr
* #return {Number}
*/
function sumArray(arr) {
var sum = 0,
i = 0,
max = arr.length;
for (; i < max; i++) {
sum += arr[i];
}
return sum;
}
console.log(combinations([1, 3, 6, 10, -1], 9));
#jcarpenter solution was so nice I just had to rework it for those that love ECMA5. This will not be as fast as the raw power of for, the modern methods have not had the length of time to be so highly optimised (and they do quite a bit more work). But the performance results do show just how good the powerSet algorithm is (and it is a reusable function). I've also filtered out the ambiguity, which slows things slightly.
Javascript
function powerSet(arr) {
var lastElement,
val;
if (!arr.length) {
val = [[]];
} else {
lastElement = arr.pop();
val = powerSet(arr).reduce(function (previous, element) {
previous.push(element);
element = element.slice();
element.push(lastElement);
previous.push(element);
return previous;
}, []);
}
return val;
}
function combinations(array, n) {
return powerSet(array).filter(function (set) {
return set.length && set.reduce(function (previous, element) {
return previous + element;
}, 0) <= n;
});
}
var a = [1, 3, 6, 10, -1];
console.log(JSON.stringify(combinations(a, 9)));
Output
[[-1],[10,-1],[6],[6,-1],[3],[3,-1],[3,6],[3,6,-1],[1],[1,-1],[1,6],[1,6,-1],[1,3],[1,3,-1],[1,3,6,-1]]
On jsFiddle
And added to the jsPerf
Try this:
var a = [1,3,6,10,-1];
function combinations(array, n) {
var arrayCopy = [],
results = [];
// duplicate the array
for (var i in array)
arrayCopy[i] = array[i];
for (var i in array)
for (var j in arrayCopy)
if ((array[i] + arrayCopy[j]) <= n)
results.push([array[i], arrayCopy[j]]);
return results;
}
console.log(combinations(a, 9));
This logged:
[1, 1], [1, 3], [1, 6], [1, -1],
[3, 1], [3, 3], [3, 6], [3, -1],
[6, 1], [6, 3], [6, -1],
[10, -1],
[-1, 1], [-1, 3], [-1, 6], [-1, 10], [-1, -1]

Javascript - range of 5 around index in array

I was wondering how to do the follow.
I have an array of objects and I'm trying to retrieve a set amount eg of them around a given index.
Here's an example.
var arr = [0,1,2,3,4,5,6,7,8,9,10];
var index = 0;
var max = 5;
If the index is 0 I want [0 - 4]
If the index is 4 I want [2 - 6]
If the index is 9 I want [6 - 10]
But I also want it to work if the array is smaller then the max too. Eg
var arr = [0,1,2];
var index = 0;
var max = 5;
Any index would return [0 - 2]
Any thoughts?
You might want to try this
var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
function getRange(array, index, range) {
var least = index - Math.floor(range/2);
least = (least < 0) ? 0 : least;
return array.slice(least, least+range);
}
var start = index - max / 2;
if (start < 0) start = 0;
var end = start + max;
if (end > arr.length) {
end = arr.length;
start = end - max;
if (start < 0) start = 0;
}
var result = arr.slice(start, end);

Categories