How to do a group by in Javascript - javascript

I have 2 arrays, a type array and an amount array:
var type = ["AB", "AB", "K1"];
var amt = [5, 2, 3];
I am having a difficult time grouping them together.
I want the output to be an array like below:
final_array = [{"AB", 7}, {"K1", 3}];
/* 7 and 3 are the sum of each type */
Note: I am guaranteed that both arrays will be the same size, and also guaranteed the order which means type[i] belongs with amt[i]. So from the example above type[0] which is "AB" belongs with amt[0] which is 5.
Thanks

This is written verbosely, but you'd use an object, and then iterate over one array checking if the keys exist in the object, if they do, just add the value to the sum, if they don't, set the value as the sum etc.
var type = [ "AB", "AB", "K1"];
var amt = [5, 2, 3];
var map = {};
type.forEach(function(x, i) {
if (x in map) {
map[x] += amt[i];
} else {
map[x] = amt[i];
}
});
document.body.innerHTML = '<pre>' + JSON.stringify(map, 0, 4) + '</pre>';
That leaves you with an object like {AB: 7, K1: 3}, which is probably what you want, but if you just have to have an array with objects that can't be looked up easily, you'd do
var arr = Object.keys(map).map(function(x) {
var o = {};
o[x] = map[x];
return o;
});
and you have [{"AB": 7}, {"K1": 3}]

var type = ["AB", "AB", "K1"];
var amt = [5, 2, 3];
var obj = {};
var final_array = [];
type.forEach(function(v, i) {
var t = obj[v];
if (t) {
t[v] += amt[i];
} else {
t = {};
t[v] = amt[i];
obj[v] = t;
}
});
Object.keys(obj).forEach(function(e) {
final_array.push(obj[e]);
});
document.write(JSON.stringify(final_array));

Related

sum of multidimensional array javascript

I want to perform the sum operation on each subarray using javascript using forEach,map,reduce function, so that ultimately my output should look like:
sum = [8,13,22]
but I am not getting the desired output. Please assist where I am going wrong.Thanks.
var Data = [{"a":1,"b":2,"c":5},{"a":3,"b":4,"c":6},{"a":6,"b":7,"c":9}];
var newArr = [];
Data.forEach(function(item) {
item = item.reduce(function(a, b) {
return a + b;
});
newArr.push([item]);
});
console.log(newArr);
You could map the summed values, literately.
var data = [{ a: 1, b: 2, c: 5 }, { a: 3, b: 4, c: 6 }, { a: 6, b: 7, c: 9 }],
result = data.map(o => Object.values(o).reduce((a, b) => a + b));
console.log(result);
Just some annotation to the given code:
You can not iterate an object with reduce, because that works only for array. To overcome this problem, you need just the values of the object by taking Object.values and then, you could iterate the values.
Then return the sum without wrapping it in an array.
var Data = [{"a":1,"b":2,"c":5},{"a":3,"b":4,"c":6},{"a":6,"b":7,"c":9}];
var newArr = [];
Data.forEach(function(item) {
var sum = Object.values(item).reduce(function(a, b) {
return a + b;
});
newArr.push(sum);
});
console.log(newArr);
A better solution would be the use of Array#map, because you need one value for each element of the array.
var data = [{"a":1,"b":2,"c":5},{"a":3,"b":4,"c":6},{"a":6,"b":7,"c":9}];
newArr = data.map(function(item) {
return Object.values(item).reduce(function(a, b) {
return a + b;
});
});
console.log(newArr);
As per your example, Old way
var Data = [{"a":1,"b":2,"c":5},{"a":3,"b":4,"c":6},{"a":6,"b":7,"c":9}];
var newArr = [];
Data.forEach(function(object) {
let sum = 0;
for (var property in object) {
if (object.hasOwnProperty(property)) {
sum += object[property]
}
}
newArr.push(sum);
});
console.log(newArr);

Checking whether certain item is in certain array using javascript

I have 10 different arrays. Each array has different numbers.
array1 = [1,2,3,4,5]
array2 = [6,7,8,9,10]
...
array 10 = [51,52,53,54]
let's say I pass in 7. Then I want to know which array it is from and want to return array number. So in this case it is going to be 2.
Should I write a switch statement for each array? Appreciate it in javascript.
try:
var arrays = [array1, array2, ..., array10];
for(var i=0; i<arrays.length; ++i) {
if (arrays[i].indexOf(value) != -1) {
console.log('found in array' + (i+1));
}
}
You cannot directly retrieve the name of array.The reason is this variable is only storing a reference to the object.
Instead you can have a key inside the same array which represent its name. Then indexOf can be used to find the array which contain the number , & if it is so, then get the array name
var array1 = [1,2,3,4,5];
array1.name ="array1";
var array2 = [6,7,8,9,10];
array2.name ="array2";
var array10 = [51,52,53,54]
array10.name ="array10";
var parArray = [array1,array2,array10]
function _getArrayName(number){
for(var o=0;o<parArray.length;o++){
var _tem = parArray[o];
if(parArray[o].indexOf(number) !==-1){
console.log(parArray[o].name);
}
}
}
_getArrayName(6) //prints array2
jsfiddle
One fast method should be using hash tables or as i would like to call LUT. Accordingly this job boils down to a single liner as follows;
var arrs = {
arr1 : [1,2,3,4,5],
arr2 : [6,7,8,9,10],
arr3 : [12,14,16,17],
arr4 : [21,23,24,25,27,20],
arr5 : [31,34,35,39],
arr6 : [45,46,44],
arr7 : [58,59],
arr8 : [66,67,69,61],
arr9 : [72,73,75,79,71],
arr0 : [81,85,98,99,90,80]
},
lut = Object.keys(arrs).reduce((p,c) => {arrs[c].forEach(n => p[n]=c); return p},{}),
findar = n => lut[n];
document.write("<pre>" + findar(12) + "</pre>");
One way to do this is have the arrays in an object and iterate over the keys/values. This method doesn't presume the arrays (and therefore their names) are in sequential order.
Note: this will always return a the first match from the function and terminate the search.
var obj = {
array1: [1, 2, 3, 4, 5],
array2: [6, 7, 8, 9, 10],
array3: [51, 52, 53, 54],
array4: [51, 52, 53, 54, 7]
}
function finder(obj, test) {
var keys = Object.keys(obj);
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
if (obj[key].indexOf(test) > -1) {
return key.match(/\d+/)[0];
}
}
return false;
}
finder(obj, 7); // '2'
DEMO
If you want to find all instances of a value in all arrays the function needs to be altered slightly.
function finder(obj, test) {
var keys = Object.keys(obj);
var out = [];
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
if (obj[key].indexOf(test) > -1) {
out.push(key.match(/\d+/)[0]);
}
}
return out;
}
finder(obj, 7); // ['2', '4']
DEMO

Output arrays in object in Javascript for spreadsheet

This is my code.
function order() {
//declare things
var order = [3, 2, 1, 0]
var testOne = [2, 3, 7, 4]
var testTwo = ["c", "b", "a", "d"]
//sort by order
var collatedArray = [];
for (var i = 0; i < order.length; i++)
{
index = order[i];
var collated =
{
test1 : testOne[index],
test2 : testTwo[index]
}
collatedArray.push(collated);
}
//Create output
var output = [];
for (i=0; i<collatedArray.length; i++)
{
output[i] = collatedArray[i].test1
}
return output
}
The output currently is only collatedArray[i].test1, which gives:
4, 7, 3, 2
If I change output[i] = collatedArray[i].test1 to test2, I get:
d, a, b, c
I just want to output the whole collatedArray (test1 and test2) so that I get:
4, 7, 3, 2
d, a, b, c
without the need for output variable, or converting back to arrays. The info is all there I just can't figure out how to get it out. Very new to coding, just not understanding what to do here :(
Thanks
Adjust output to an array containing two arrays; within last for loop populate each array within output with values at collatedArray[0][i].test1 and collatedArray[1][i].test2
// Create output
var output = [[], []];
for (i=0; i<collatedArray.length; i++)
{
output[0][i] = collatedArray[i].test1;
output[1][i] = collatedArray[i].test2;
}
function order() {
//declare things
var order = [3, 2, 1, 0]
var testOne = [2, 3, 7, 4]
var testTwo = ["c", "b", "a", "d"]
//sort by order
var collatedArray = [];
for (var i = 0; i < order.length; i++) {
index = order[i];
var collated = {
test1: testOne[index],
test2: testTwo[index]
}
collatedArray.push(collated);
}
//Create output
var output = [
[],
[]
];
for (i = 0; i < collatedArray.length; i++) {
output[0][i] = collatedArray[i].test1;
output[1][i] = collatedArray[i].test2;
}
return output
}
console.log(order())
There are several ways that you can do this, including storing each testNumber (testOne, testTwo, etc) in an object consisting of properties. Learn how objects work and you should, having observed your code here, easily be able to figure out how to loop through each property (which in your case will be arrays) of said Object to print out what you're looking for. If you can't figure it out, there are plenty of Stack Overflow Q&A's that cover this phenomenally well.
But for now, here is a simple alternative: an array of arrays.
https://jsfiddle.net/6r3hv3aq/7/
var testOne = [2,3,7,4];
var testTwo = ["c","b","a","d"];
var test = [testOne,testTwo];
for (var i = 0; i <= test.length-1; i++) {
console.log(test[i]);
}
Which will output exactly what you asked for:
[2, 3, 7, 4]
["c", "b", "a", "d"]
Note: When you click the jsfiddle link provided, you may have to refresh the page to see the appropriate results loaded into the console. Alternatively, leave the console open when you migrate to the link.
Since you're wanting this for a spreadsheet I am assuming you want a CSV output string that you can import into a spreadsheet program.
function row(source, sequence) {
var temp = new Array(sequence.length);
for (var i = 0; i < sequence.length; i++)
temp[i] = source[sequence[i]];
return temp.join(",")
}
function order() {
//declare things
var sequence = [3, 2, 1, 0];
var testOne = [2, 3, 7, 4];
var testTwo = ["c", "b", "a", "d"];
var rows = [];
rows.push(row(testOne, sequence));
rows.push(row(testTwo, sequence));
return rows.join("\r\n");
}
Here's a plunkr

Combining two arrays with different number of elements

Let’s assume we have this two arrays:
x = [1, 2, 3];
y = ['a', 'b'];
What would be the best way to combine them and get the following result:
newArray = ['1a', '1b', '2a', '2b', '3a', '3b'];
Here is one way of doing that:
x.reduce(function(arr, x) {
return arr.concat(y.map(function(y) {
return x + y;
}));
}, []);
//=> ["1a", "1b", "2a", "2b", "3a", "3b"]
Try this:
var x = [1, 2, 3];
var y = ['a', 'b'];
var output = [];
for (var i = 0; i < x.length; i++) {
for (var j = 0; j < y.length; j++) {
output.push(x[i]+y[j]);
}
}
document.getElementById('output').innerHTML = JSON.stringify(output);
<div id="output"></div>
Try this..
var x = [1, 2, 3];
var y = ['a', 'b'];
var newarr = [];
for(var i=0;i<x.length;i++){
for(var j=0;j<y.length;j++){
newarr.push(x[i]+y[j]);
}
}
//alert(newarr);
DEMO
If arrow functions are supported you obtain the desired result like this:
[].concat.apply([],
x.map(x => y.map(y => x+y))
);
If not, you have to write it like this
[].concat.apply([],
x.map(function(x) { return y.map(function(y) {return x+y })})
);
Explanation:
The middle line yields the following result:
[ ["1a", "1b"], ["2a", "2b"], ["3a", "3b"] ]
Then the Array.prototype.concat method is used to concatenate the inner arrays.
You could simply create a array to be returned and do a simple loop for the array that contains numbers. Inside of that loop, you create another loop for the array of combinations to the numbers (var b=0,e=comb.length;e>b;b++). Using the i from the first loop (for(var i=0,l=array.length;l>i;i++)) you push the array at it (a[i]) with the array of combinations at the position b (c[b]) (inside of the loop that's inside of the first loop) to the new array. Finally, return the new array.
function CombineExample(a,c){
var New=[];
for(var i=0,l=a.length;l>i;i++){
for(var b=0,e=c.length;e>b;b++){
New.push(a[i]+c[b])
}
}
return New
}
Clean! And do this to use:
CombineExample([1,2,3],['a','b'])
/* returns ["1a", "1b", "2a", "2b", "3a", "3b"] */
Use nested loops to iterate all elements of the participating arrays. Populate new array elements inside the inner loop:
var x = [1, 2, 3];
var y = ['a', 'b'];
var newArray = [];
x.forEach(function(xItem) {
y.forEach(function(yItem) {
newArray.push(xItem.toString().concat(yItem));
});
});
console.log(newArray);
The simplest approach:
var x = ["a", "b", "c"];
var y = [1, 2, 3];
var newArray = [];
var i = 0;
for (;i < x.length;++i) {
var j = 0;
for (;j < y.length;++j) {
newArray.push(x[i] + y[j]);
}
}
;
Please do note that if both arrays are numeric, this will actually add the numbers, not concatenate. You'd need to do some string conversion.
var x = [1, 2, 3];
var y = ['a', 'b'];
var z = [];
for(var i=0;i<x.length;i++){
for(var j=0;j<y.length;j++){
z.push(x[i]+y[j]);
}
}
Are you seriously asking for that?

Javascript, repeating an object key N-times, being N its value

I was wondering how to do this in the more cleaner and optimal way:
I have an Object with the following structure:
{
"125": 2,
"439": 3,
"560": 1,
"999": 2,
...
}
I want to create a flat array repeating every key, the number of times indicated by its value. And bonus points for converting keys (strings) to integers. In this example, the resulting array should be:
[ 125, 125, 439, 439, 439, 560, 999, 999 ]
I've tried several ways but they all look over-engineered. For sure there is an easier way.
This is what I've got with underscore (and it returns an Array of strings, nor integers):
_.compact(_.flatten(_.map(files, function(num, id) {
return new Array(num+1).join('$'+id).split('$')
})))
I know there are plenty of ways to accomplish this. I just only want a clean and quick way. Being a Ruby developer it could be as easy as:
> files = {"125" => 2, "439" => 3, "560" => 1, "999" => 2}
=> {"125"=>2, "439"=>3, "560"=>1, "999"=>2}
> files.map {|key, value| [key.to_i] * value}.flatten
=> [125, 125, 439, 439, 439, 560, 999, 999]
Thanks in advance.
Try this:
var obj = {
"125": 2,
"439": 3,
"560": 1,
"999": 2
}
var arr = [];
for (prop in obj) {
for (var i = 0; i < obj[prop]; i++)
arr.push(parseInt(prop));
}
console.log(arr)
I know this is plain JavaScript but seems cleaner to me than the code you posted:
var dict = {
"125": 2,
"439": 3,
"560": 1,
"999": 2
}
var result = [];
for(key in dict)
for(i = 0; i < dict[key]; i++)
result.push(key * 1);
alert(result);
Hmm... not sure if I got at, but maybe something like this:
var myObj = {
"125": 2,
"439": 3,
"560": 1,
"999": 2
},
myArray = [];
for(k in myObj){
for(i = 0; i < myObj[k]; i++){
myArray.push(k);
}
}
console.log(myArray)
The problem with the other answers above is that the for..in language construct in javascript is going to involve all keys from the objects prototype chain. In this case, we should check and add only the correct keys.
var obj= {
"125": 2,
"439": 3,
"560": 1,
"999": 2
}
var arr=[];
for (var item in map) {
//important check!
if (map.hasOwnProperty(item)) {
arr.push(item);
}
}
Also see: http://www.yuiblog.com/blog/2006/09/26/for-in-intrigue/
Whether any of these approaches is cleaner is quite subjective:
// some helper function for creating an array with repeated values
function repeat(val, times) {
var arr = [];
for(var i = 0; i < times; i = arr.push(val));
return arr;
}
function convert(obj) {
var result = [], key;
for(key in obj) {
result = result.concat(repeat(+key, obj[key]));
}
return result;
}
Or a more functional approach:
Object.keys(obj).reduce(function(result, key) {
return result.concat(repeat(+key, obj[key]));
}, []);
// with underscore.js
_.reduce(_.keys(obj), function(result, key) {
return result.concat(repeat(+key, obj[key]));
}, []);
A helper function:
function flatten(obj){
//static Array method: create array (a elements, value b)
Array.aXb = Array.aXb || function(a,b){
b = b || 0;
return String(this(a)).split(',').map(function(){return b;});
}
//obj2array
var arr = [];
for (var k in obj)
if (+obj[k]) arr = arr.concat(Array.aXb(+obj[k],k));
return arr;
}
var obj= {"125": 2,"439": 3,
"560": 1,"999": 2 },
flatten(obj); //=> [125,125,439,439,439,560,999,999]

Categories

Resources