0

I am creating a list of words from a String. I then split that string into individual words, gather a count of how many times each word is repeated, and display it. Everything there works perfectly. However, the result displays the words and counts in no specific order. I will want to display them with the highest number first. I have generated the following code:

<!DOCTYPE html>
<html>
<body>

<p>Click the button to display the array values after the split.</p>

<button onclick="analyze()">Analyze</button>

<p id="displayText"></p>

<script>
function analyze() {
    var str = "This this is is is is is is is is is is is is is is is just just a test test test";
    var res = str.split(" ");
    document.getElementById("displayText").innerHTML = res;
    document.getElementById("displayText").innerHTML += "<br/><br/>The amount of words is: " + res.length + "<br/><br/><br/>";

    document.getElementById("displayText").innerHTML += "The list of words:<br/><br/>";

    var words = [];

    var wordsWithCount = [];

    for (i = 0; i < res.length; i++) {
        words.push(res[i]);
        document.getElementById("displayText").innerHTML += words[i] + "<br/><br/>";
    }

    var current = null;
    var cnt = 0;
    for (var i = 0; i < words.length; i++) {
        if (words[i] != current) {
            if (cnt > 0) {
                document.getElementById("displayText").innerHTML += "<br/><br/>" + cnt + " - " + current + "<br/>";
                wordsWithCount.push(cnt + " - " + current);
            }
            current = words[i];
            cnt = 1;
        } else {
            cnt++;
        }
    }

    if (cnt > 0) {
        document.getElementById("displayText").innerHTML += "<br/><br/>" + cnt + " - " + current + "<br/>";
        wordsWithCount.push(cnt + " - " + current);
    }

    wordsWithCount.sort();

    document.getElementById("displayText").innerHTML += "<br/><br/><br/><br/><br/>The list of SORTED words:<br/><br/>";

    for (i = 0; i < wordsWithCount.length; i++) {
        document.getElementById("displayText").innerHTML += wordsWithCount[i] + "<br/><br/>";
    }
}
</script>

</body>
</html>

This is the last bit of the output. As you can see, it's being sorted, but only by first digit. Thus, 15 is displayed before 2. Any thoughts?

The list of SORTED words:

1 - This

1 - a

1 - this

15 - is

2 - just

3 - test

I will most likely need to break this into two arrays at some point, because I will want the user to be able to copy and paste all of the words, without the numbers. However, I assume that will need to be the last step, because if I break the frequency of each word into it's own array of numbers, and keep the words in their own array, then the sort function will sort one array, and the other array will not follow.

Ryan
  • 511
  • 1
  • 8
  • 18
  • 2
    `parseInt()` doesn't care if there's non-numeric text *after* a number at the start of a string. – Pointy May 10 '17 at 20:33
  • @Pointy, can you clarify your answer for me a bit? Are you saying I can use `parseInt()` somewhere in my code to make it do what I'm looking for? Can you provide me with an example of how I can use that? – Ryan May 10 '17 at 20:35
  • https://stackoverflow.com/questions/15478954/sort-array-elements-string-with-numbers-natural-sort – Bergi May 10 '17 at 20:49
  • @Ryan Hope my solution helped. If so, please consider marking my answer as a correct solution. – Sterling Beason May 11 '17 at 04:17

3 Answers3

1

Do it using Intl.Collator. Like this:

var collator = new Intl.Collator(undefined, {numeric: true, sensitivity: 'base'});
var test = ['1 - this', '3 - this', '14 - this'];
test.sort(collator.compare);

Outputs ["1 - this", "3 - this", "14 - this"]

var collator = new Intl.Collator(undefined, {numeric: true, sensitivity: 'base'});
    var test = ['1 - this', '3 - this', '14 - this'];
    console.log(test.sort(collator.compare));
gaganshera
  • 2,629
  • 1
  • 14
  • 21
1

Using a parseInt() method and the solution found here (How to sort an array of integers correctly) to the mix it works!

replace wordsWithCount.sort(); with:

function sortNumber(a,b) {
      return parseInt(a) - parseInt(b);
}

wordsWithCount.sort(sortNumber);

Live here: https://www.w3schools.com/code/tryit.asp?filename=FFGXRIN0VZWO

Community
  • 1
  • 1
Sterling Beason
  • 622
  • 6
  • 12
0

You can just add a custom compare function to pass into your wordsWithCount.sort() call. Here I declared a function called compareWordCount and used the sugfested method by @Pointy; using parseInt to ignore all non integer parts appended to array value. Take a look at this working snippet:

<!DOCTYPE html>
<html>
<body>

<p>Click the button to display the array values after the split.</p>

<button onclick="analyze()">Analyze</button>

<p id="displayText"></p>

<script>
function compareWordCount(a,b) {
  if (parseInt(a) < parseInt(b))
    return -1;
  return 1;
}

function analyze() {
    var str = "This this is is is is is is is is is is is is is is is just just a test test test";
    var res = str.split(" ");
    document.getElementById("displayText").innerHTML = res;
    document.getElementById("displayText").innerHTML += "<br/><br/>The amount of words is: " + res.length + "<br/><br/><br/>";

    document.getElementById("displayText").innerHTML += "The list of words:<br/><br/>";

    var words = [];

    var wordsWithCount = [];

    for (i = 0; i < res.length; i++) {
        words.push(res[i]);
        document.getElementById("displayText").innerHTML += words[i] + "<br/><br/>";
    }

    var current = null;
    var cnt = 0;
    for (var i = 0; i < words.length; i++) {
        if (words[i] != current) {
            if (cnt > 0) {
                document.getElementById("displayText").innerHTML += "<br/><br/>" + cnt + " - " + current + "<br/>";
                wordsWithCount.push(cnt + " - " + current);
            }
            current = words[i];
            cnt = 1;
        } else {
            cnt++;
        }
    }

    if (cnt > 0) {
        document.getElementById("displayText").innerHTML += "<br/><br/>" + cnt + " - " + current + "<br/>";
        wordsWithCount.push(cnt + " - " + current);
    }

    wordsWithCount.sort(compareWordCount);

    document.getElementById("displayText").innerHTML += "<br/><br/><br/><br/><br/>The list of SORTED words:<br/><br/>";

    for (i = 0; i < wordsWithCount.length; i++) {
        document.getElementById("displayText").innerHTML += wordsWithCount[i] + "<br/><br/>";
    }
}
</script>

</body>
</html>
Sasang
  • 1,261
  • 9
  • 10
  • Your comparator function is incorrect in the case the two numbers are the same. In that case, the function should return `0` not `1`, and yes it definitely matters. – Pointy May 10 '17 at 20:44