2

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?

9
  • Are external libraries allowed? This should be a one-liner with underscore.js Commented Oct 19, 2013 at 9:20
  • No, just jquery internally hosted. Commented Oct 19, 2013 at 9:21
  • 1
    also, do you have an idea? It should be easy to find a solution Commented Oct 19, 2013 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. Commented Oct 19, 2013 at 9:26
  • 1
    @JanDvorak, unfortunately not. Same elements follow arbitrary order, which is why is keeping me busy for so long. Commented Oct 19, 2013 at 9:48

5 Answers 5

4

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]});
  }
}
Sign up to request clarification or add additional context in comments.

3 Comments

@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.
Excellent, love it! The step by step was very useful. Thanks a lot.
@rid I've never heard of such a bug. Since jQuery makes that assumption, this bug cannot happen in IE8+.
1

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 ] ]

2 Comments

This looks very similar to mine ;-)
@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
-1

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.

10 Comments

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.
document.write removed and i used console.log. It should print.
as noted by rid, you still should collect the results in an array, not print it out anywhere.
close, but I don't think a string with a key and frequency is useful ;-)
Please take a look on my code. The result will be stored in result_array
|
-1

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);

3 Comments

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).
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.
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 ;-)
-1
$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>";
    }

3 Comments

wrong language, and you don't even sort the output as requested.
Jan Dvorak- Sorry for language, now check its work as you required
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.