Take the tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I have:

myArray = ["ABAB", "ABAB", "ABAB", "CDCD", "EFEF", "EFEF"]

I need to count by occurrences and sort by highest count. This would be the return:

ABAB 3
EFEF 2
CDCD 1

Note, the parameters inside the array are constantly changed so by "grepping" for each static or literal text pattern won't help.

Any idea of the fastest way to accomplish this either with JQuery or plain JS?

share|improve this question
 
Are external libraries allowed? This should be a one-liner with underscore.js –  Jan Dvorak Oct 19 at 9:20
 
No, just jquery internally hosted. –  rebHelium Oct 19 at 9:21
1  
also, do you have an idea? It should be easy to find a solution –  Jan Dvorak Oct 19 at 9:23
1  
well, you could loop through the array and place every unique item in its own array in a temp object. Then check if your object has an array where the first element is the same as the current one... if so, add to that array. –  kasper Taeymans Oct 19 at 9:26
1  
@JanDvorak, unfortunately not. Same elements follow arbitrary order, which is why is keeping me busy for so long. –  rebHelium Oct 19 at 9:48
show 4 more comments

5 Answers

up vote 5 down vote accepted

Step one: build the histogram, as a map element -> its frequency for speed (assumes all elements are strings):

var histogramMap = {};
for(var i=0, len=myArray.length; i<len; i++){
  var key = myArray[i];
  histogramMap[key] = (histogramMap[key] || 0) + 1;
}

Step two: convert to an array of output objects:

var histogram = [];
for(key in histogramMap) histogram.push({key: key, freq: histogramMap[key]});

Step three: sort the histogram

histogram.sort(function(a,b){return b.freq - a.freq})

This also assumes that Object.prototype is not modified. This is a safe assumption to make, and lots (I think) of libraries, including jQuery, make that assumption. But, if you decide to add enumerable properties to Object.prototype, these will be picked up by for..in. If you want to be safe, modify the second step to:

var histogram = [];
for(key in histogramMap){
  if(histogramMap.hasOwnProperty(i)){
    histogram.push({key: key, freq: histogramMap[key]});
  }
}
share|improve this answer
 
@rid jQuery assumes Object.prototype has no enumerable properties. In the situations where hasOwnProperty is needed in my code, jQuery breaks ;-) I habitually leave out hasOwnProperty when looping over plain objects. –  Jan Dvorak Oct 19 at 9:57
 
Excellent, love it! The step by step was very useful. Thanks a lot. –  rebHelium Oct 19 at 9:59
 
@rid I've never heard of such a bug. Since jQuery makes that assumption, this bug cannot happen in IE8+. –  Jan Dvorak Oct 19 at 10:08
add comment

I recently created a library with such a function.

var items = {}, sortableItems = [], i, len, element,
    listOfStrings = ["ABAB", "ABAB", "ABAB", "CDCD", "EFEF", "EFEF"];

for (i = 0, len = listOfStrings.length; i < len; i += 1) {
    if (items.hasOwnProperty(listOfStrings[i])) {
        items[listOfStrings[i]] += 1;
    } else {
        items[listOfStrings[i]] = 1;
    }
}

for (element in items) {
    if (items.hasOwnProperty(element)) {
        sortableItems.push([element, items[element]]);
    }
}

sortableItems.sort(function (first, second) {
    return second[1] - first[1];
});

console.log(sortableItems);

Output

[ [ 'ABAB', 3 ], [ 'EFEF', 2 ], [ 'CDCD', 1 ] ]
share|improve this answer
 
This looks very similar to mine ;-) –  Jan Dvorak Oct 19 at 14:25
 
@JanDvorak I think there is only one way to do this ;) And I wrote this code few weeks back. github.com/thefourtheye/XString/blob/master/XString.js#L40 –  thefourtheye Oct 19 at 14:47
add comment

see console in firefox to see the resulting object

http://jsfiddle.net/4dqeK/1/

myArray = ["ABAB", "ABAB", "ABAB", "CDCD", "EFEF", "EFEF"];

container={};

 for(var i=0; i < myArray.length;i++){
        var el=myArray[i];
        if( el in container){
            container[el].push(el);
        }
        else{
            container[el]=[];
            container[el].push(el);
        }


    }
    console.log(container);
share|improve this answer
 
don't use for..in for arrays. You could pick up shimmed methods and other non-numeric properties. Also, the iteration order is not specified (not really an issue here). –  Jan Dvorak Oct 19 at 9:44
 
also, I don't think an array ["abab", "abab", "abab"] is an efficient way to represent that "abab" occurs three times. Also, you don't sort the results by frequency. –  Jan Dvorak Oct 19 at 9:46
 
hi, I'm just demonstrating how this can be done. of course this is not the most efficient way. you could easily make it better. btw I edited my answer to get rid of the for in, you're right about that. I just used for in because it's quicker typed ;-) –  kasper Taeymans Oct 19 at 9:50
add comment

Try this:

array_elements = ["ABAB", "ABAB", "ABAB", "CDCD", "EFEF", "EFEF"];

var result_array = [];

var current = null;
var cnt = 0;
for (var i = 0; i < array_elements.length; i++) {
    if (array_elements[i] != current) {
        if (cnt > 0) {
            result_array.push([current,cnt]);
        }
        current = array_elements[i];
        cnt = 1;
    } else {
        cnt++;
    }
}
if (cnt > 0) {
    result_array.push([current,cnt]);
}

result_array.sort(function(x,y) {return y[1] - x[1]})
alert(result_array);

The result_array will have the result.

share|improve this answer
 
Why down vote? reason? –  suresh.g Oct 19 at 9:31
 
don't use document.write. One, it's evil. Two, you don't know if your code is running at the moment when DW is just slow. Third, you are not supposed to print anything. –  Jan Dvorak Oct 19 at 9:31
 
document.write removed and i used console.log. It should print. –  suresh.g Oct 19 at 9:33
 
as noted by rid, you still should collect the results in an array, not print it out anywhere. –  Jan Dvorak Oct 19 at 9:34
 
close, but I don't think a string with a key and frequency is useful ;-) –  Jan Dvorak Oct 19 at 9:37
show 9 more comments
$array = array("ABAB", "ABAB", "ABAB", "CDCD", "EFEF", "EFEF");
   $array1=array_count_values($array);

    arsort($array1);


    foreach($array1 as $x=>$x_value)
    {
        echo "Key=" . $x . ", Value=" . $x_value;
        echo "<br>";
    }
share|improve this answer
 
wrong language, and you don't even sort the output as requested. –  Jan Dvorak Oct 19 at 10:54
 
Jan Dvorak- Sorry for language, now check its work as you required –  Sandesh Oct 21 at 4:28
 
It's still in PHP, thus not useful in a javascript environment (and this is a javascript question). Especially since all the implementation is hidden in a few library calls that pure javascript doesn't have. Also, please don't use <br>s. Even for testing, <p>s work better. –  Jan Dvorak Oct 21 at 4:33
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.