Reputation: 323
I need to look through an array of unknown values and count how many of each unique values there are and push the count and value into a new array. So let's say I have the following array:
["123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891"]
I want to take this array and get the following array out of it:
["123", 12, "456", 12, "678", 12, "891", 12]
This gets the value and the number of times it occurs no matter how many and what values are in the original array:
["value", number of occurences]
Here is my attempt at accomplishing this, that kinda worked, but it is very gross and I want to learn/use a cleaner method.
function _sortData(data) {
var tempDataHolder = [];
var dataId = data[0];
var matches = 0;
var dataLength = data.length;
for (var i = 0; i <= dataLength - 1; i++) {
if(dataId === data[i]) {
matches++;
data.splice(i, 1);
i--;
} else if(data.length === 1 && dataId === data[0]) {
matches++;
}
if(i >= data.length){
tempDataHolder.push(dataId, matches);
if(data[0]){
i = 0;
dataLength = data.length;
dataId = data[0];
matches = 0;
}
}
}
return tempDataHolder;
}
EDIT: Man there are some awesome answers here. What would you guys say is the "best" solution? Either way I'm learning a lot from all the answers and they seem to all solve my issue.
Upvotes: 0
Views: 86
Reputation: 791
I would save the occurrences into a count
object. This takes advantage of the fact that every object in JS is basically a HashMap
.
var inputArr = ["123", "456", "67","123", "456"... ];
var counter = {};
var outArr = [];
inputArr.foreach(function(number) {
if(counter[number])
counter[number] = counter[number] + 1;
else
counter[number] = 1;
});
for (var prop in counter) {
if(counter.hasOwnProperty(prop)) {
outArr.push([prop], counter[prop]);
}
}
return outArr;
The above contains a little pseudocode for inputArr
that will need to be corrected but this should work just fine without multiple iterations of any objects or arrays.
Upvotes: 1
Reputation: 350477
Here is a solution using reduce
and Object.keys
:
function sortData(data) {
var map = data.reduce(function (map, val) {
map[val] = (map[val] || 0) + 1;
return map;
}, {});
return Object.keys(map).reduce(function (result, key) {
return result.concat([key, map[key]]);
}, []);
}
// Test it:
var data = ["123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891"];
var result = sortData(data);
console.log(result);
Upvotes: 1
Reputation: 792
Here's a solution :
var hashMap = {};
var list = ["123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891"];
list.forEach(function(u){
if (!hashMap.hasOwnProperty(u)){
hashMap[u] = 1;
}
else {
hashMap[u] += 1;
}
})
// hashMap : {
// "123" : 12,
// "456" : 12,
// "678" : 12,
// "891" : 12
// }
And if you want an array of the unique values :
var uniqueList = Object.keys(hashMap);
//uniqueList : ["123", "456", "678", "891"];
Upvotes: 1
Reputation: 9782
This approach uses the values in the array as property names and the property value is the number of times it is in the array.
// Input array
var gazinta = ["123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678",
"891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891",
"123", "456", "678", "891", "123", "456", "678", "891"];
var gazada;
gazada = countEmUp(gazinta);
console.log(gazada);
function countEmUp(gazinta) {
// i is a counter
// counted is an object where the value to be counted is the property name and the value is the count
// flattened is a single-dimensional array with each value followed by its count
var i, counted = {}, flattened = [];
// Loop through the array
for (i = 0; i < gazinta.length; i++) {
// If this is a new element, meaning the property doesn't exist in the counted object
if (typeof counted[gazinta[i]] === "undefined") {
// Initialize it to zero
counted[gazinta[i]] = 0;
}
// Increment the counter
counted[gazinta[i]]++;
}
// Loop through the counted object and push the elements and counts onto the flattened array
for (i in counted) {
flattened.push(i,counted[i]);
}
return flattened;
}
Upvotes: 1
Reputation: 195
You can use a javascript object with the elements as keys and the count as values. Once you have looped through the original array you can loop through the hash map and convert to the array you desire.
JS
var a = ["123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891", "123", "456", "678", "891"];
var counter = {};
for ( var i = 0; i < a.length ; i ++) {
var currentKey = a[i];
if(counter.hasOwnProperty(currentKey)) {
counter[currentKey] += 1;
} else {
counter[currentKey] = 1;
}
}
Counter will be a hashmap of value <--> count pairs:
Object {123: 12, 456: 12, 678: 12, 891: 12}
You can loop through the object and convert it to the array desired:
var condensedArr = [];
for (var key in counter) {
condensedArr.push(key);
condensedArr.push(counter[key]);
}
Here is a working JSFiddle
Upvotes: 1