How to rollup data points using underscore.js? - javascript

Say I have an array of 6 numeric data points and want to change it to an array of 3 data points where each point is the sum of a 2 of the points
[1,1,1,1,1,1] ~> [2,2,2]
What is the best way to do this with a library like underscore.js

If you wanted to do it in a generic, functional way, then
function allowIndexes(idx) {
return function(item, index) {
return index % idx;
}
}
function sum() {
return _.reduce(_.toArray(arguments)[0], function(result, current) {
return result + current;
}, 0);
}
var isIndexOdd = allowIndexes(2);
var zipped = _.zip(_.reject(data, isIndexOdd), _.filter(data, isIndexOdd));
console.log(_.map(zipped, sum));
# [ 3, 7, 11 ]
But, this will be no where near the performance of
var result = [];
for (var i = 0; i < data.length; i += 2) {
result.push(data[i] + data[i + 1]);
}
console.log(result);

I found one way. I'll gladly accept a better solution.
values = [1,1,1,1,1,1];
reportingPeriod = 2;
var combined = [];
_.inject( values, function ( total, value, index) {
if ((index + 1) % reportingPeriod === 0) {
combined.push(total + value);
return 0;
} else {
return total + value
}
}, 0);

Using lodash, you could do the following:
let arr = _.fill(Array(6), 1);
let reducer = (sum, num) => sum += num;
arr = _.chain(arr).chunk(2).map(arr => arr.reduce(reducer)).value();

Related

Javascript how to optimise this count array values function

I have a function that mimics the array_count_values function from php in javascript but it's not very fast. I'm wondering if there's a way to fix it?
function array_count_values(arr) {
let a = [], prev;
arr.sort();
for ( let i = 0; i < arr.length; i++ ) {
if ( arr[i] !== prev ) {
a.push(1)
} else {
a[a.length-1]++;
}
prev = arr[i];
}
return a;
}
It just returns a simple array of numbers with the counts so like 2,1,2,1,1. The input in this case would be numeric arrays 5-7 elements long, so for example array_count_values([6,4,10,6,6])
You can use reduce to loop thru the array and count each entry.
function array_count_values(arr) {
return arr.reduce((c, v) => {
c[v] = c[v] || 0;
c[v]++;
return c;
}, {})
}
var result = array_count_values([6, 4, 10, 6, 6]);
console.log(result);
You could take an object for counting and omit sorting. This approach uses a single loop.
function array_count_values(array) {
var count = {},
i;
for (i = 0; i < array.length; i++) {
if (array[i] in count) {
count[array[i]]++;
} else {
count[array[i]] = 1;
}
}
return Object.values(count).sort((a, b) => b - a);
}
console.log(array_count_values([6, 4, 10, 6, 6]));
This is actually a straight-forward algorithm. I've been brushing up on them lately:
var array_count_values = function(array) {
let dict = {};
for (var i = 0; i < array.length; i++ ) {
var num = array[i];
(dict[num]) ? dict[num]++ : dict[num] = 1;
}
return dict;
}
console.log(array_count_values([6, 4, 10, 6, 6]));
Time and space complexity is both O(n).
I think the addition of a sort here is overkill, and probably the slowest part of this.
I think this will be the fastest/simplest way you can do this.
function array_count_values(arr) {
let outputCounts = {};
for ( let i = 0; i < arr.length; i++ ) {
if (outputCounts[arr[i]] != undefined){
outputCounts[arr[i]] += 1;
} else {
outputCounts[arr[i]] = 1;
}
}
return outputCounts;
}
The caveat here is that you're going to get an object back instead of an array as in your example.
const arr = [1, 2, 2, 3];
function array_count_values (arr) {
const frequencies = arr.reduce((f, v) => {
const freq = f.get(v) || 0;
f.set(v, freq + 1);
return f;
}, new Map());
return arr.map(v => frequencies.get(v));
}
console.log(array_count_values(arr));
Looking at how array_count_values works in php. This might be what you are looking for
function array_count_values(arr) {
return arr.reduce((acc, val) => {
if (!acc[val]) {
acc[val] = 0
}
acc[val] += 1
return acc
}, {})
}
To return an array as required in the question
function array_count_values(arr) {
return Object.values(arr.reduce((acc, val) => {
if (!acc[val]) {
acc[val] = 0
}
acc[val] += 1
return acc
}, {}))
}

Get array value sums based on other array key values

I have an array similar to this:
var programs_array = [
{"id":3543,"category":"1","target_revenue":1845608},
{"id":2823,"category":"1","target_revenue":1627994},
{"id":1611,"category":"1","target_revenue":1450852},
{"id":1624,"category":"1","target_revenue":25473},
{"id":4626,"category":"2","target_revenue":253048},
{"id":5792,"category":"2","target_revenue":298468},
{"id":5799,"category":"2","target_revenue":256815},
{"id":5171,"category":"2","target_revenue":239090},
{"id":4064,"category":"3","target_revenue":119048},
{"id":2322,"category":"3","target_revenue":59146},
{"id":3466,"category":"3","target_revenue":29362},
{"id":3442,"category":"3","target_revenue":149860},
{"id":1254,"category":"3","target_revenue":15600},
{"id":1685,"category":"3","target_revenue":45463}
];
I want the sum of all "target_revenue" values if "category" equals 2. Currently, I'm doing this, but I'd like to ensure I'm doing this the most efficient way.
Array.prototype.sum_cat = function (prop, cat, val) {
var total = 0
for ( var i = 0, _len = this.length; i < _len; i++ ) {
if(this[i][cat]==val){total += this[i][prop]}
}
return total
}
console.log('total 2: '+programs_array.sum_cat('target_revenue','category',2));
Here's a fiddle: https://jsfiddle.net/26v48djp/
I would use reduce, adding to the accumulator if category is 2:
const programs_array=[{"id":3543,"category":"1","target_revenue":1845608},{"id":2823,"category":"1","target_revenue":1627994},{"id":1611,"category":"1","target_revenue":1450852},{"id":1624,"category":"1","target_revenue":25473},{"id":4626,"category":"2","target_revenue":253048},{"id":5792,"category":"2","target_revenue":298468},{"id":5799,"category":"2","target_revenue":256815},{"id":5171,"category":"2","target_revenue":239090},{"id":4064,"category":"3","target_revenue":119048},{"id":2322,"category":"3","target_revenue":59146},{"id":3466,"category":"3","target_revenue":29362},{"id":3442,"category":"3","target_revenue":149860},{"id":1254,"category":"3","target_revenue":15600},{"id":1685,"category":"3","target_revenue":45463}]
const getSum = (findCat) => programs_array.reduce((a, { category, target_revenue }) => (
category === findCat
? a + target_revenue
: a
), 0);
console.log(getSum("2"));
You could chain filter with a reduce to accomplish this easily and concisely.
const sum = programs_array.filter(e => e.category === '2').reduce((acc, element) => acc + element.target_revenue);
Or if you wanted a slightly more performant, but less concise way you could do the following. But the difference for an array of this size is likely negligible.
const sum = programs_array.reduce((acc, element) => {
return element.category === '2' ? (acc + element.target_revenue) : acc;
});
You can simply achieve this using array.reduce()
let arr = [{"id":3543,"category":"1","target_revenue":1845608}, {"id":2823,"category":"1","target_revenue":1627994}, {"id":1611,"category":"1","target_revenue":1450852}, {"id":1624,"category":"1","target_revenue":25473}, {"id":4626,"category":"2","target_revenue":253048}, {"id":5792,"category":"2","target_revenue":298468}, {"id":5799,"category":"2","target_revenue":256815}, {"id":5171,"category":"2","target_revenue":239090}, {"id":4064,"category":"3","target_revenue":119048}, {"id":2322,"category":"3","target_revenue":59146}, {"id":3466,"category":"3","target_revenue":29362}, {"id":3442,"category":"3","target_revenue":149860}, {"id":1254,"category":"3","target_revenue":15600}, {"id":1685,"category":"3","target_revenue":45463} ];
function getSum(prop, val){
return arr.reduce((a,curr)=> curr.category === val ? a + curr[prop] : a,0);
}
console.log(getSum("target_revenue", "2"));
In general, a for loop is going to be the most efficient solution.
See: https://hackernoon.com/javascript-performance-test-for-vs-for-each-vs-map-reduce-filter-find-32c1113f19d7
I would use your code with slight modifications as seen below:
Array.prototype.sum_cat = function (prop, cat, val) {
let total = 0,
_len = this.length;
for (let i = 0; i < _len; i++) {
if (this[i][cat] == val) { total += this[i][prop]; }
}
return total;
}
console.log('total 2: '+programs_array.sum_cat('target_revenue','category',2));

How to find the most duplicate "values" in javascript array?

my question is actually similar to: Extracting the most duplicate value from an array in JavaScript (with jQuery)
I Found this but it always return one value only which is 200.
var arr = [100,100,200,200,200,300,300,300,400,400,400];
var counts = {}, max = 0, res;
for (var v in arr) {
counts[arr[v]] = (counts[arr[v]] || 0) + 1;
if (counts[arr[v]] > max) {
max = counts[arr[v]];
res = arr[v];
}
}
console.log(res + " occurs " + counts[res] + " times");
pls help me to return values not just one...
The result is should like this:
200,300,400
.
pls help thank you!
You have to iterate your counts to find the max occurred result.
var arr = [100,100,200,200,200,300,300,300,400,400,400];
var counts = {}, max = 0, res;
for (var v in arr) {
counts[arr[v]] = (counts[arr[v]] || 0) + 1;
if (counts[arr[v]] > max) {
max = counts[arr[v]];
res = arr[v];
}
}
var results = [];
for (var k in counts){
if (counts[k] == max){
//console.log(k + " occurs " + counts[k] + " times");
results.push(k);
}
}
console.log(results);
Create a Object iterating the arry containing the indexes of most repeated values, like below
var arr = [100,100,200,200,200,300,300,300,400,400,400];
valObj = {}, max_length = 0, rep_arr = [];
arr.forEach(function(el,i){
if(valObj.hasOwnProperty(el)){
valObj[el] += 1;
max_length = (valObj[el] > max_length) ? valObj[el] : max_length
}
else{
valObj[el] = 1;
}
});
Object.keys(valObj).forEach(function(val){
(valObj[val] >= max_length) && (rep_arr.push(val))
});
console.log(rep_arr);
After the object is created with key as array value and value as array indexes of that value, you can play/parse that. Hope this helps.
Iterating an array using for..in is not a good idea. Check this link for more information.
Hopefully below snippet will be useful
var arr = [100, 100, 200, 200, 200, 300, 300, 300, 400, 400, 400];
//Use a reduce fuction to create an object where 100,200,300
// will be keys and its value will the number of times it has
//repeated
var m = arr.reduce(function(i, v) {
if (i[v] === undefined) {
i[v] = 1
} else {
i[v] = i[v] + 1;
}
return i;
}, {});
// Now get the maximum value from that object,
//getMaxRepeated will be 3 in this case
var getMaxRepeated = Math.max(...Object.values(m));
//An array to hold elements which are repeated 'getMaxRepeated' times
var duplicateItems = [];
// now iterate that object and push the keys which are repeated
//getMaxRepeated times
for (var keys in m) {
if (m[keys] === getMaxRepeated) {
duplicateItems.push(keys)
}
}
console.log(duplicateItems)
The following would do the trick assuming that all items in arr are numbers:
//added some numbers assuming numbers are not sorted
var arr = [300,400,200,100,100,200,200,200,300,300,300,400,400,400];
var obj = arr.reduce(//reduce arr to object of: {"100":2,"200":4,"300":4,"400":4}
(o,key)=>{//key is 100,200, ... o is {"100":numberOfOccurrences,"200":numberOf...}
o[key] = (o[key])?o[key]+1:1;
return o;
},
{}
);
// obj is now: {"100":2,"200":4,"300":4,"400":4}
//create an array of [{key:100,occurs:2},{key:200,occurs:4}...
var sorted = Object.keys(obj).map(
key=>({key:parseInt(key),occurs:obj[key]})
)//sort the [{key:100,occurs:2},... by highest occurrences then lowest key
.sort(
(a,b)=>
(b.occurs-a.occurs===0)
? a.key - b.key
: b.occurs - a.occurs
);
console.log(
sorted.filter(//only the highest occurrences
item=>item.occurs===sorted[0].occurs
).map(//only the number; not the occurrences
item=>item.key
)
);
Try as following ==>
function getDuplicate( arr ){
let obj = {}, dup = [];
for(let i = 0, l = arr.length; i < l; i++){
let val = arr[i];
if( obj[val] /**[hasOwnProperty]*/ ) {
/**[is exists]*/
if(dup.find(a => a == val) ) continue;
/**[put Unique One]*/
dup.push(val);
continue;
};
/**[hold for further use]*/
obj[val] = true;
}
return dup;
};
Use ==>
getDuplicate([100,100,200,200,200,300,300,300,400,400,400]);
Try the following:
var candles = [100,100,200,200,200,300,300,300,400,400,400];
let tempArray = {}
for (let index = 0; index <= (candles.length - 1); index++) {
let valueToCompare = candles[index];
if (tempArray[valueToCompare]) {
tempArray[valueToCompare] = tempArray[valueToCompare] + 1;
} else {
tempArray[valueToCompare] = 1;
}
}
let highestValue;
Object.values(tempArray).forEach(item => {
if (highestValue === undefined) highestValue = item;
if (highestValue < item) highestValue = item;
});
console.log(highestValue);

Javascript reduce() until sum of values < variable

I am fetching an array of video durations (in seconds) from a JSON file in Javascript, that, to simplify, would look like this:
array = [30, 30, 30]
I would like to add each value to the previous value until a condition is met (the sum being less than a variable x) and then to get both the new value and the index position in the array of the video to play.
For example if x=62 (condition), I would like the first two values in the array to be added (from my understanding reduce() is appropriate here), and the index = 2 (the second video in the array).
I've got the grasp of reduce():
var count = array.reduce(function(prev, curr, index) {
console.log(prev, curr, index);
return prev + curr;
});
But can't seem to get beyond this point.. Thanks
You could use Array#some, which breaks on a condition.
var array = [30, 30, 30],
x = 62,
index,
sum = 0;
array.some(function (a, i) {
index = i;
if (sum + a > x) {
return true;
}
sum += a;
});
console.log(index, sum);
With a compact result and this args
var array = [30, 30, 30],
x = 62,
result = { index: -1, sum: 0 };
array.some(function (a, i) {
this.index = i;
if (this.sum + a > x) {
return true;
}
this.sum += a;
}, result);
console.log(result);
var a = [2,4,5,7,8];
var index;
var result = [0, 1, 2, 3].reduce(function(a, b,i) {
var sum = a+b;
if(sum<11){
index=i;
return sum;
}
}, 2);
console.log(result,index);
What about using a for loop? This is hack-free:
function sumUntil(array, threshold) {
let i
let result = 0
// we loop til the end of the array
// or right before result > threshold
for(i = 0; i < array.length && result+array[i] < threshold; i++) {
result += array[i]
}
return {
index: i - 1, // -1 because it is incremented at the end of the last loop
result
}
}
console.log(
sumUntil( [30, 30, 30], 62 )
)
// {index: 1, result: 60}
bonus: replace let with var and it works on IE5.5
You could do
var limit = 60;
var array = [30,30,30];
var count = array.reduce(function(prev, curr, index) {
var temp = prev.sum + curr;
if (index != -1) {
if (temp > limit) {
prev.index = index;
} else {
prev.sum = temp;
}
}
return prev;
}, {
sum: 0,
index: -1
});
console.log(count);
What about this : https://jsfiddle.net/rtcgpgk2/1/
var count = 0; //starting index
var arrayToCheck = [20, 30, 40, 20, 50]; //array to check
var condition = 100; //condition to be more than
increment(arrayToCheck, count, condition); //call function
function increment(array, index, conditionalValue) {
var total = 0; //total to add to
for (var i = 0; i < index; i++) { //loop through array up to index
total += array[i]; //add value of array at index to total
}
if (total < conditionalValue) { //if condition is not met
count++; //increment index
increment(arrayToCheck, count, condition); //call function
} else { //otherwise
console.log('Index : ', count) //log what index condition is met
}
}
// define the max outside of the reduce
var max = 20;
var hitIndex;
var count = array.reduce(function(prev, curr, index) {
let r = prev + curr;
// if r is less than max keep adding
if (r < max) {
return r
} else {
// if hitIndex is undefined set it to the current index
hitIndex = hitIndex === undefined ? index : hitIndex;
return prev;
}
});
console.log(count, hitIndex);
This will leave you with the index of the first addition that would exceed the max. You could try index - 1 for the first value that did not exceed it.
You can create a small utility method reduceWhile
// Javascript reduceWhile implementation
function reduceWhile(predicate, reducer, initValue, coll) {
return coll.reduce(function(accumulator, val) {
if (!predicate(accumulator, val)) return accumulator;
return reducer(accumulator, val);
}, initValue)
};
function predicate(accumulator, val) {
return val < 6;
}
function reducer(accumulator, val) {
return accumulator += val;
}
var result = reduceWhile(predicate, reducer, 0, [1, 2, 3, 4, 5, 6, 7])
console.log("result", result);

Generate permutations of JavaScript array [duplicate]

This question already has answers here:
Permutations in JavaScript?
(41 answers)
Closed 1 year ago.
I have an array of n different elements in javascript, I know there are n! possible ways to order these elements. I want to know what's the most effective (fastest) algorithm to generate all possible orderings of this array?
I have this code:
var swap = function(array, frstElm, scndElm) {
var temp = array[frstElm];
array[frstElm] = array[scndElm];
array[scndElm] = temp;
}
var permutation = function(array, leftIndex, size) {
var x;
if(leftIndex === size) {
temp = "";
for (var i = 0; i < array.length; i++) {
temp += array[i] + " ";
}
console.log("---------------> " + temp);
} else {
for(x = leftIndex; x < size; x++) {
swap(array, leftIndex, x);
permutation(array, leftIndex + 1, size);
swap(array, leftIndex, x);
}
}
}
arrCities = ["Sidney", "Melbourne", "Queenstown"];
permutation(arrCities, 0, arrCities.length);
And it works, but I guess swapping every item to get the combinations is a bit expensive memory wise, I thought a good way of doing it is just focusing on the indexes of the array and getting all the permutations of the numbers, I'm wondering if there's a way of computing all of them without having to switch elements within the array? I guess recursively is possible to get all of them, I need help to do so.
So for example if I have:
arrCities = ["Sidney", "Melbourne", "Queenstown"];
I want the output to be:
[[012],[021],[102],[120],[201],[210]]
or:
[[0,1,2],
[0,2,1],
[1,0,2],
[1,2,0],
[2,0,1],
[2,1,0]]
I'm reading this:
http://en.wikipedia.org/wiki/Permutation#Algorithms_to_generate_permutations
But Wikipedia has never been good at explaining. I don't understand much of it, I have to say my math level isn't the best.
This function, perm(xs), returns all the permutations of a given array:
function perm(xs) {
let ret = [];
for (let i = 0; i < xs.length; i = i + 1) {
let rest = perm(xs.slice(0, i).concat(xs.slice(i + 1)));
if(!rest.length) {
ret.push([xs[i]])
} else {
for(let j = 0; j < rest.length; j = j + 1) {
ret.push([xs[i]].concat(rest[j]))
}
}
}
return ret;
}
console.log(perm([1,2,3]).join("\n"));
Using Heap's method (you can find it in this paper which your Wikipedia article links to), you can generate all permutations of N elements with runtime complexity in O(N!) and space complexity in O(N). This algorithm is based on swapping elements. AFAIK this is as fast as it gets, there is no faster method to calculate all permutations.
For an implementation and examples, please have a look at my recent answer at the related question "permutations in javascript".
It is just for fun - my recursive solve in one string
const perm = a => a.length ? a.reduce((r, v, i) => [ ...r, ...perm([ ...a.slice(0, i), ...a.slice(i + 1) ]).map(x => [ v, ...x ])], []) : [[]]
This is my version based on le_m's code:
function permute(array) {
Array.prototype.swap = function (index, otherIndex) {
var valueAtIndex = this[index]
this[index] = this[otherIndex]
this[otherIndex] = valueAtIndex
}
var result = [array.slice()]
, length = array.length
for (var i = 1, heap = new Array(length).fill(0)
; i < length
;)
if (heap[i] < i) {
array.swap(i, i % 2 && heap[i])
result.push(array.slice())
heap[i]++
i = 1
} else {
heap[i] = 0
i++
}
return result
}
console.log(permute([1, 2, 3]))
This is my recursive JavaScript implementation of the same algorithm:
Array.prototype.swap = function (index, otherIndex) {
var valueAtIndex = this[index]
this[index] = this[otherIndex]
this[otherIndex] = valueAtIndex
}
Array.prototype.permutation = function permutation(array, n) {
array = array || this
n = n || array.length
var result = []
if (n == 1)
result = [array.slice()]
else {
const nextN = n - 1
for (var i = 0; i < nextN; i++) {
result.push(...permutation(array, nextN))
array.swap(Number(!(n % 2)) && i, nextN)
}
result.push(...permutation(array, nextN))
}
return result
}
console.log([1, 2, 3].permutation())
function permutations(str) {
return (str.length <= 1) ? [str] :
Array.from(new Set(
str.split('')
.map((char, i) => permutations(str.substr(0, i) + str.substr(i + 1)).map(p => char + p))
.reduce((r, x) => r.concat(x), [])
));
}

Categories

Resources