ARRAY javascript indexOf - javascript

I have a multi-dimensional array. I need some sort of loop to randomly pick a string in the array and check to see if that string contains a character. If it doesn't, then repeat until it finds one.
I wrote a for loop that checks the array for the string, BUT it starts from 0 and works its way through the array until it finds it. I need it randomly pick a string in the array...any help?
jsFiddle --> http://jsfiddle.net/hz2MZ/1/
jQuery
$(document).ready(function() {
var myarr = [{"Name":"Bob", "Char":"134"},
{"Name":"Phil", "Char":"134"},
{"Name":"Jane", "Char":"1"},
{"Name":"Don", "Char":"4"},
{"Name":"Dan", "Char":"2"},
{"Name":"Jan", "Char":"12"},
{"Name":"Bill", "Char":"24"},
{"Name":"Sam", "Char":"14"},
{"Name":"Jake", "Char":"23"},
{"Name":"Ben", "Char":"3"}];
$('button').click(function() {
for(var i = 0; i < myarr.length; i++) {
if(myarr[i].Char.indexOf('2') !== -1) {
alert("Name: " + myarr[i].Name + "\nChar: " + myarr[i].Char);
return;
} else {}
}
});
});

My solution
$('button').click(function () {
var found = false;
while (!found) {
var randomIndex = Math.floor(Math.random() * myarr.length);
if (myarr[randomIndex].Char.indexOf('2') !== -1) {
alert("Name: " + myarr[randomIndex].Name + "\nChar: " + myarr[randomIndex].Char);
found = true;
} else {}
}
});
edit
Updated endless loop problem
$('button').click(function () {
var found = false;
var maxRandom = 20;
var currentRandom = 0;
while (!found && currentRandom < maxRandom) {
var randomIndex = Math.floor((Math.random() * myarr.length));
currentRandom++;
if (myarr[randomIndex].Char.indexOf('2') !== -1) {
alert("Name: " + myarr[randomIndex].Name + "\nChar: " + myarr[randomIndex].Char);
found = true;
} else {}
}
}

One approach is to copy the array, then randomly splice one member from the copy and check for the required value:
function randomValueByChar(arr, c) {
var a = arr.slice && arr.slice();
var i = a.length || 0;
var t;
while (i--) {
t = a.splice(Math.random() * i | 0, 1);
if (t[0].Char.indexOf(c) != -1) return t;
}
}
Another approach is to create an array of the indexes (e.g. [0,1,2,3…]), then randomly splice one value at a time and use it as an index to retrieve a value from the array. Both approaches will not have an infinite loop and will visit each member a maximum of once.

Related

How can I extract all contained characters in a String? [duplicate]

I have a string with repeated letters. I want letters that are repeated more than once to show only once.
Example input: aaabbbccc
Expected output: abc
I've tried to create the code myself, but so far my function has the following problems:
if the letter doesn't repeat, it's not shown (it should be)
if it's repeated once, it's show only once (i.e. aa shows a - correct)
if it's repeated twice, shows all (i.e. aaa shows aaa - should be a)
if it's repeated 3 times, it shows 6 (if aaaa it shows aaaaaa - should be a)
function unique_char(string) {
var unique = '';
var count = 0;
for (var i = 0; i < string.length; i++) {
for (var j = i+1; j < string.length; j++) {
if (string[i] == string[j]) {
count++;
unique += string[i];
}
}
}
return unique;
}
document.write(unique_char('aaabbbccc'));
The function must be with loop inside a loop; that's why the second for is inside the first.
Fill a Set with the characters and concatenate its unique entries:
function unique(str) {
return String.prototype.concat.call(...new Set(str));
}
console.log(unique('abc')); // "abc"
console.log(unique('abcabc')); // "abc"
Convert it to an array first, then use Josh Mc’s answer at How to get unique values in an array, and rejoin, like so:
var nonUnique = "ababdefegg";
var unique = Array.from(nonUnique).filter(function(item, i, ar){ return ar.indexOf(item) === i; }).join('');
All in one line. :-)
Too late may be but still my version of answer to this post:
function extractUniqCharacters(str){
var temp = {};
for(var oindex=0;oindex<str.length;oindex++){
temp[str.charAt(oindex)] = 0; //Assign any value
}
return Object.keys(temp).join("");
}
You can use a regular expression with a custom replacement function:
function unique_char(string) {
return string.replace(/(.)\1*/g, function(sequence, char) {
if (sequence.length == 1) // if the letter doesn't repeat
return ""; // its not shown
if (sequence.length == 2) // if its repeated once
return char; // its show only once (if aa shows a)
if (sequence.length == 3) // if its repeated twice
return sequence; // shows all(if aaa shows aaa)
if (sequence.length == 4) // if its repeated 3 times
return Array(7).join(char); // it shows 6( if aaaa shows aaaaaa)
// else ???
return sequence;
});
}
Using lodash:
_.uniq('aaabbbccc').join(''); // gives 'abc'
Per the actual question: "if the letter doesn't repeat its not shown"
function unique_char(str)
{
var obj = new Object();
for (var i = 0; i < str.length; i++)
{
var chr = str[i];
if (chr in obj)
{
obj[chr] += 1;
}
else
{
obj[chr] = 1;
}
}
var multiples = [];
for (key in obj)
{
// Remove this test if you just want unique chars
// But still keep the multiples.push(key)
if (obj[key] > 1)
{
multiples.push(key);
}
}
return multiples.join("");
}
var str = "aaabbbccc";
document.write(unique_char(str));
Your problem is that you are adding to unique every time you find the character in string. Really you should probably do something like this (since you specified the answer must be a nested for loop):
function unique_char(string){
var str_length=string.length;
var unique='';
for(var i=0; i<str_length; i++){
var foundIt = false;
for(var j=0; j<unique.length; j++){
if(string[i]==unique[j]){
foundIt = true;
break;
}
}
if(!foundIt){
unique+=string[i];
}
}
return unique;
}
document.write( unique_char('aaabbbccc'))
In this we only add the character found in string to unique if it isn't already there. This is really not an efficient way to do this at all ... but based on your requirements it should work.
I can't run this since I don't have anything handy to run JavaScript in ... but the theory in this method should work.
Try this if duplicate characters have to be displayed once, i.e.,
for i/p: aaabbbccc o/p: abc
var str="aaabbbccc";
Array.prototype.map.call(str,
(obj,i)=>{
if(str.indexOf(obj,i+1)==-1 ){
return obj;
}
}
).join("");
//output: "abc"
And try this if only unique characters(String Bombarding Algo) have to be displayed, add another "and" condition to remove the characters which came more than once and display only unique characters, i.e.,
for i/p: aabbbkaha o/p: kh
var str="aabbbkaha";
Array.prototype.map.call(str,
(obj,i)=>{
if(str.indexOf(obj,i+1)==-1 && str.lastIndexOf(obj,i-1)==-1){ // another and condition
return obj;
}
}
).join("");
//output: "kh"
<script>
uniqueString = "";
alert("Displays the number of a specific character in user entered string and then finds the number of unique characters:");
function countChar(testString, lookFor) {
var charCounter = 0;
document.write("Looking at this string:<br>");
for (pos = 0; pos < testString.length; pos++) {
if (testString.charAt(pos) == lookFor) {
charCounter += 1;
document.write("<B>" + lookFor + "</B>");
} else
document.write(testString.charAt(pos));
}
document.write("<br><br>");
return charCounter;
}
function findNumberOfUniqueChar(testString) {
var numChar = 0,
uniqueChar = 0;
for (pos = 0; pos < testString.length; pos++) {
var newLookFor = "";
for (pos2 = 0; pos2 <= pos; pos2++) {
if (testString.charAt(pos) == testString.charAt(pos2)) {
numChar += 1;
}
}
if (numChar == 1) {
uniqueChar += 1;
uniqueString = uniqueString + " " + testString.charAt(pos)
}
numChar = 0;
}
return uniqueChar;
}
var testString = prompt("Give me a string of characters to check", "");
var lookFor = "startvalue";
while (lookFor.length > 1) {
if (lookFor != "startvalue")
alert("Please select only one character");
lookFor = prompt(testString + "\n\nWhat should character should I look for?", "");
}
document.write("I found " + countChar(testString, lookFor) + " of the<b> " + lookFor + "</B> character");
document.write("<br><br>I counted the following " + findNumberOfUniqueChar(testString) + " unique character(s):");
document.write("<br>" + uniqueString)
</script>
Here is the simplest function to do that
function remove(text)
{
var unique= "";
for(var i = 0; i < text.length; i++)
{
if(unique.indexOf(text.charAt(i)) < 0)
{
unique += text.charAt(i);
}
}
return unique;
}
The one line solution will be to use Set. const chars = [...new Set(s.split(''))];
If you want to return values in an array, you can use this function below.
const getUniqueChar = (str) => Array.from(str)
.filter((item, index, arr) => arr.slice(index + 1).indexOf(item) === -1);
console.log(getUniqueChar("aaabbbccc"));
Alternatively, you can use the Set constructor.
const getUniqueChar = (str) => new Set(str);
console.log(getUniqueChar("aaabbbccc"));
Here is the simplest function to do that pt. 2
const showUniqChars = (text) => {
let uniqChars = "";
for (const char of text) {
if (!uniqChars.includes(char))
uniqChars += char;
}
return uniqChars;
};
const countUnique = (s1, s2) => new Set(s1 + s2).size
a shorter way based on #le_m answer
let unique=myArray.filter((item,index,array)=>array.indexOf(item)===index)

Javascript: randomly pair items from array without repeats

I am trying to make a very basic "secret santa" generator as one of my first Javascript projects. I have searched for hours for a solution to this problem but so far nothing has worked that I have found.
I have an array of names which need paired to each other. I successfully have them pairing to each other, but right now someone can be drawn twice. I am pushing the randomly chosen names to another array but I can't find a way to check the randomly chosen names against the ones already chosen.
var names = ["Sean","Kyle","Emily","Nick","Cotter","Brian","Jeremy","Kimmy","Pat","Johnny"];
var used = [];
var picks = [];
if (names.length % 2 != 0) {
alert("You must have an even number of names. You currently have " + names.length + " names.");
}
for( var i = 0; i < names.length; i++){
var random = Math.floor(Math.random()*names.length)
if(names[random] == names[i]) {
names[random] = names[random++];
picks.push(names[i] + " gets " + names[random]);
used.push(names[random]);
} else {
picks.push(names[i] + " gets " + names[random]);
used.push(names[random]);
}
}
console.log("picked array: ")
for(var k=0; k<picks.length; k++) {
console.log(picks[k]);
}
console.log("used array: " + used);
Thank you in advance for any help.
Create two arrays with the names, shuffle them, and make sure you don't pick the same name from both arrays :
var names = ["Sean","Kyle","Emily","Nick","Cotter","Brian","Jeremy","Kimmy","Pat","Johnny"];
if (names.length % 2 != 0) {
alert("You must have an even number of names. You currently have " + names.length + " names.");
} else {
var arr1 = names.slice(), // copy array
arr2 = names.slice(); // copy array again
arr1.sort(function() { return 0.5 - Math.random();}); // shuffle arrays
arr2.sort(function() { return 0.5 - Math.random();});
while (arr1.length) {
var name1 = arr1.pop(), // get the last value of arr1
name2 = arr2[0] == name1 ? arr2.pop() : arr2.shift();
// ^^ if the first value is the same as name1,
// get the last value, otherwise get the first
console.log(name1 + ' gets ' + name2);
}
}
FIDDLE
I would suggest a different approach. Shuffle, split, and zip, no mutation:
var splitAt = function(i, xs) {
var a = xs.slice(0, i);
var b = xs.slice(i, xs.length);
return [a, b];
};
var shuffle = function(xs) {
return xs.slice(0).sort(function() {
return .5 - Math.random();
});
};
var zip = function(xs) {
return xs[0].map(function(_,i) {
return xs.map(function(x) {
return x[i];
});
});
}
// Obviously assumes even array
var result = zip(splitAt(names.length/2, shuffle(names)));
//^
// [
// [ 'Nick', 'Kimmy' ],
// [ 'Sean', 'Johnny' ],
// [ 'Kyle', 'Brian' ],
// [ 'Cotter', 'Pat' ],
// [ 'Emily', 'Jeremy' ]
// ]
There is a multitude of ways you can achieve this.
The fastest to code, but not necessarily the randomest is:
var names = ["Sean","Kyle","Emily","Nick","Cotter","Brian","Jeremy","Kimmy","Pat","Johnny"];
function getPicks(names) {
return names.slice(0).sort(function(){ return Math.random()-0.5 }).map(function(name, index, arr){
return name + " gets " + arr[(index+1)%arr.length];
});
}
getPicks(names);
This is not very random because the shuffling isn't very good and also because you get a single cycle each time. There can be no two cycles A->B->C->A D->E->D.
If you want it to have a random number of cycles of variable length, you can split the names array in several arrays and do the above for each of them, then concatenate the results (see elclanrs).
Finally, the last solution is for each person to pick a person at random and if it's the same one, simply pick again. If the last name remaining in both arrays is the same, simply swap it with another pair.
var names = ["Sean","Kyle","Emily","Nick","Cotter","Brian","Jeremy","Kimmy","Pat","Johnny"];
var a = names.slice(0);
var b = names.slice(0);
var result = [];
while (a.length > 1) {
var i = extractRandomElement(a);
var j = extractRandomElement(b);
while (i===j) {
b.push(j);
j = extractRandomElement(b);
}
result.push({ a:i, b:j });
}
if (a[0] === b[0]) {
result.push({ a:a[0], b:result[0].b });
result[0].b = a[0];
} else {
result.push({ a:a[0], b:b[0] });
}
var pairs = result.map(function(item){ return item.a + ' gets ' + item.b});
function extractRandomElement(array) {
return array.splice(Math.floor(Math.random()*array.length),1)[0];
}
I'm a tad late, but thought I'd throw my answer in here. It essentially does the same thing #adeneo's does, but it uses the same basic code as OP:
var names = ["Sean","Kyle","Emily","Nick","Cotter","Brian","Jeremy","Kimmy","Pat","Johnny"];
pickpool = names.slice(0); // Slice the array at the first element to copy it by value
var used = [];
var picks = [];
if (names.length % 2 != 0) {
alert("You must have an even number of names. You currently have " + names.length + " names.");
}
for( var i = 0; i < names.length; i++){
var random = Math.floor(Math.random()*pickpool.length)
if(names[random] == names[i]) {
// names[random] = names[random++];
picks.push(names[i] + " gets " + pickpool[random++]);
pickpool.splice(random++,1);
} else {
picks.push(names[i] + " gets " + pickpool[random]);
pickpool.splice(random,1);
}
}
console.log("picked array: ");
for(var k=0; k<picks.length; k++) {
console.log(picks[k]);
}
http://jsfiddle.net/SNJpC/
If you don't need to keep the original array you can remove the names as they get selected and each time you pick a name check that it isn't an empty string before pushing it to the next array.
Another consideration...
If you are trying to make a 'Secret Santa' generator, by using random method you can get the same pair next year, and next...
This is another solution where you get all the possible pairs (without repeating a name itself or a pair) for multiple years.
var names = ["Sean", "Kyle", "Emily", "Nick", "Cotter", "Brian", "Jeremy", "Kimmy", "Pat", "Johnny"];
if (names.length % 2 != 0) {
alert("You must have an even number of names. You currently have " + names.length + " names.");
} else {
const arr1 = names.slice()
let arr2 = names.slice();
let countDown = number => {
if (number === 1) {
return;
}
const last = arr2.pop([number - 1]);
arr2.unshift(last);
let pairs = [];
arr1.map(item => {
const index = arr1.indexOf(item);
pairs.push(`${arr1[index]} gets ${arr2[index]}`)
})
console.log(pairs)
return countDown(number - 1);
}
countDown(names.length)
}

Javascript: Random number out of 5, no repeat until all have been used

I am using the below code to assign a random class (out of five) to each individual image on my page.
$(this).addClass('color-' + (Math.floor(Math.random() * 5) + 1));
It's working great but I want to make it so that there are never two of the same class in a row.
Even better would be if there were never two of the same in a row, and it also did not use any class more than once until all 5 had been used... As in, remove each used class from the array until all of them have been used, then start again, not allowing the last of the previous 5 and the first of the next 5 to be the same color.
Hope that makes sense, and thanks in advance for any help.
You need to create an array of the possible values and each time you retrieve a random index from the array to use one of the values, you remove it from the array.
Here's a general purpose random function that will not repeat until all values have been used. You can call this and then just add this index onto the end of your class name.
var uniqueRandoms = [];
var numRandoms = 5;
function makeUniqueRandom() {
// refill the array if needed
if (!uniqueRandoms.length) {
for (var i = 0; i < numRandoms; i++) {
uniqueRandoms.push(i);
}
}
var index = Math.floor(Math.random() * uniqueRandoms.length);
var val = uniqueRandoms[index];
// now remove that value from the array
uniqueRandoms.splice(index, 1);
return val;
}
Working demo: http://jsfiddle.net/jfriend00/H9bLH/
So, your code would just be this:
$(this).addClass('color-' + (makeUniqueRandom() + 1));
Here's an object oriented form that will allow more than one of these to be used in different places in your app:
// if only one argument is passed, it will assume that is the high
// limit and the low limit will be set to zero
// so you can use either r = new randomeGenerator(9);
// or r = new randomGenerator(0, 9);
function randomGenerator(low, high) {
if (arguments.length < 2) {
high = low;
low = 0;
}
this.low = low;
this.high = high;
this.reset();
}
randomGenerator.prototype = {
reset: function() {
this.remaining = [];
for (var i = this.low; i <= this.high; i++) {
this.remaining.push(i);
}
},
get: function() {
if (!this.remaining.length) {
this.reset();
}
var index = Math.floor(Math.random() * this.remaining.length);
var val = this.remaining[index];
this.remaining.splice(index, 1);
return val;
}
}
Sample Usage:
var r = new randomGenerator(1, 9);
var rand1 = r.get();
var rand2 = r.get();
Working demo: http://jsfiddle.net/jfriend00/q36Lk4hk/
You can do something like this using an array and the splice method:
var classes = ["color-1", "color-2", "color-3", "color-4", "color-5"];
for(i = 0;i < 5; i++){
var randomPosition = Math.floor(Math.random() * classes.length);
var selected = classes.splice(randomPosition,1);
console.log(selected);
alert(selected);
}
var used = [];
var range = [0, 5];
var generateColors = (function() {
var current;
for ( var i = range[0]; i < range[5]; i++ ) {
while ( used.indexOf(current = (Math.floor(Math.random() * 5) + 1)) != -1 ) ;
used.push(current);
$(" SELECTOR ").addClass('color-' + current);
}
});
Just to explain my comment to jfriend00's excellent answer, you can have a function that returns the members of a set in random order until all have been returned, then starts again, e.g.:
function RandomList(list) {
var original = list;
this.getOriginal = function() {
return original;
}
}
RandomList.prototype.getRandom = function() {
if (!(this.remainder && this.remainder.length)) {
this.remainder = this.getOriginal().slice();
}
return this.remainder.splice(Math.random() * this.remainder.length | 0,1);
}
var list = new RandomList([1,2,3]);
list.getRandom(); // returns a random member of list without repeating until all
// members have been returned.
If the list can be hard coded, you can keep the original in a closure, e.g.
var randomItem = (function() {
var original = [1,2,3];
var remainder;
return function() {
if (!(remainder && remainder.length)) {
remainder = original.slice();
}
return remainder.splice(Math.random() * remainder.length | 0, 1);
};
}());

remove value from comma separated values string

I have a csv string like this "1,2,3" and want to be able to remove a desired value from it.
For example if I want to remove the value: 2, the output string should be the following:
"1,3"
I'm using the following code but seems to be ineffective.
var values = selectedvalues.split(",");
if (values.length > 0) {
for (var i = 0; i < values.length; i++) {
if (values[i] == value) {
index = i;
break;
}
}
if (index != -1) {
selectedvalues = selectedvalues.substring(0, index + 1) + selectedvalues.substring(index + 3);
}
}
else {
selectedvalues = "";
}
var removeValue = function(list, value, separator) {
separator = separator || ",";
var values = list.split(separator);
for(var i = 0 ; i < values.length ; i++) {
if(values[i] == value) {
values.splice(i, 1);
return values.join(separator);
}
}
return list;
}
If the value you're looking for is found, it's removed, and a new comma delimited list returned. If it is not found, the old list is returned.
Thanks to Grant Wagner for pointing out my code mistake and enhancement!
John Resign (jQuery, Mozilla) has a neat article about JavaScript Array Remove which you might find useful.
function removeValue(list, value) {
return list.replace(new RegExp(",?" + value + ",?"), function(match) {
var first_comma = match.charAt(0) === ',',
second_comma;
if (first_comma &&
(second_comma = match.charAt(match.length - 1) === ',')) {
return ',';
}
return '';
});
};
alert(removeValue('1,2,3', '1')); // 2,3
alert(removeValue('1,2,3', '2')); // 1,3
alert(removeValue('1,2,3', '3')); // 1,2
values is now an array. So instead of doing the traversing yourself.
Do:
var index = values.indexOf(value);
if(index >= 0) {
values.splice(index, 1);
}
removing a single object from a given index.
hope this helps
Here are 2 possible solutions:
function removeValue(list, value) {
return list.replace(new RegExp(value + ',?'), '')
}
function removeValue(list, value) {
list = list.split(',');
list.splice(list.indexOf(value), 1);
return list.join(',');
}
removeValue('1,2,3', '2'); // "1,3"
Note that this will only remove first occurrence of a value.
Also note that Array.prototype.indexOf is not part of ECMAScript ed. 3 (it was introduced in JavaScript 1.6 - implemented in all modern implementations except JScript one - and is now codified in ES5).
// Note that if the source is not a proper CSV string, the function will return a blank string ("").
function removeCsvVal(var source, var toRemove) //source is a string of comma-seperated values,
{ //toRemove is the CSV to remove all instances of
var sourceArr = source.split(","); //Split the CSV's by commas
var toReturn = ""; //Declare the new string we're going to create
for (var i = 0; i < sourceArr.length; i++) //Check all of the elements in the array
{
if (sourceArr[i] != toRemove) //If the item is not equal
toReturn += sourceArr[i] + ","; //add it to the return string
}
return toReturn.substr(0, toReturn.length - 1); //remove trailing comma
}
To apply it too your var values:
var values = removeVsvVal(selectedvalues, "2");
guess im too slow but here is what i would do
<script language="javascript">
function Remove(value,replaceValue)
{ var result = ","+value+",";
result = result.replace(","+replaceValue+",",",");
result = result.substr(1,result.length);
result = result.substr(0,result.length-1);
alert(result);
}
Remove("1,2,3",2)
</script>
adding , before and after the string ensure that u only remove the exact string u want
function process(csv,valueToDelete) {
var tmp = ","+csv;
tmp = tmp.replace(","+valueToDelete,"");
if (tmp.substr(0,1) == ',') tmp = tmp.substr(1);
return tmp;
}
use splice, pop or shift. depending on your requirement.
You could also have "find" the indexes of items in your array that match by using a function like the one found here : http://www.hunlock.com/blogs/Ten_Javascript_Tools_Everyone_Should_Have
var tmp = [5,9,12,18,56,1,10,42,'blue',30, 7,97,53,33,30,35,27,30,'35','Ball', 'bubble'];
// 0/1/2 /3 /4/5 /6 /7 /8 /9/10/11/12/13/14/15/16/17/ 18/ 19/ 20
var thirty=tmp.find(30); // Returns 9, 14, 17
var thirtyfive=tmp.find('35'); // Returns 18
var thirtyfive=tmp.find(35); // Returns 15
var haveBlue=tmp.find('blue'); // Returns 8
var notFound=tmp.find('not there!'); // Returns false
var regexp1=tmp.find(/^b/); // returns 8,20 (first letter starts with b)
var regexp1=tmp.find(/^b/i); // returns 8,19,20 (same as above but ignore case)
Array.prototype.find = function(searchStr) {
var returnArray = false;
for (i=0; i<this.length; i++) {
if (typeof(searchStr) == 'function') {
if (searchStr.test(this[i])) {
if (!returnArray) { returnArray = [] }
returnArray.push(i);
}
} else {
if (this[i]===searchStr) {
if (!returnArray) { returnArray = [] }
returnArray.push(i);
}
}
}
return returnArray;
}
or
var csv_remove_val = function(s, val, sep) {
var sep = sep || ",", a = s.split(sep), val = ""+val, pos;
while ((pos = a.indexOf(val)) >= 0) a.splice(pos, 1);
return a.join(sep);
}

What's the best way to count keywords in JavaScript?

What's the best and most efficient way to count keywords in JavaScript? Basically, I'd like to take a string and get the top N words or phrases that occur in the string, mainly for the use of suggesting tags. I'm looking more for conceptual hints or links to real-life examples than actual code, but I certainly wouldn't mind if you'd like to share code as well. If there are particular functions that would help, I'd also appreciate that.
Right now I think I'm at using the split() function to separate the string by spaces and then cleaning punctuation out with a regular expression. I'd also want it to be case-insensitive.
Cut, paste + execute demo:
var text = "Text to be examined to determine which n words are used the most";
// Find 'em!
var wordRegExp = /\w+(?:'\w{1,2})?/g;
var words = {};
var matches;
while ((matches = wordRegExp.exec(text)) != null)
{
var word = matches[0].toLowerCase();
if (typeof words[word] == "undefined")
{
words[word] = 1;
}
else
{
words[word]++;
}
}
// Sort 'em!
var wordList = [];
for (var word in words)
{
if (words.hasOwnProperty(word))
{
wordList.push([word, words[word]]);
}
}
wordList.sort(function(a, b) { return b[1] - a[1]; });
// Come back any time, straaanger!
var n = 10;
var message = ["The top " + n + " words are:"];
for (var i = 0; i < n; i++)
{
message.push(wordList[i][0] + " - " + wordList[i][1] + " occurance" +
(wordList[i][1] == 1 ? "" : "s"));
}
alert(message.join("\n"));
Reusable function:
function getTopNWords(text, n)
{
var wordRegExp = /\w+(?:'\w{1,2})?/g;
var words = {};
var matches;
while ((matches = wordRegExp.exec(text)) != null)
{
var word = matches[0].toLowerCase();
if (typeof words[word] == "undefined")
{
words[word] = 1;
}
else
{
words[word]++;
}
}
var wordList = [];
for (var word in words)
{
if (words.hasOwnProperty(word))
{
wordList.push([word, words[word]]);
}
}
wordList.sort(function(a, b) { return b[1] - a[1]; });
var topWords = [];
for (var i = 0; i < n; i++)
{
topWords.push(wordList[i][0]);
}
return topWords;
}
Once you have that array of words cleaned up, and let's say you call it wordArray:
var keywordRegistry = {};
for(var i = 0; i < wordArray.length; i++) {
if(keywordRegistry.hasOwnProperty(wordArray[i]) == false) {
keywordRegistry[wordArray[i]] = 0;
}
keywordRegistry[wordArray[i]] = keywordRegistry[wordArray[i]] + 1;
}
// now keywordRegistry will have, as properties, all of the
// words in your word array with their respective counts
// this will alert (choose something better than alert) all words and their counts
for(var keyword in keywordRegistry) {
alert("The keyword '" + keyword + "' occurred " + keywordRegistry[keyword] + " times");
}
That should give you the basics of doing this part of the work.
Try to split you string on words and count the resulting words, then sort on the counts.
This builds upon a previous answer by insin by only having one loop:
function top_words(text, n) {
// Split text on non word characters
var words = text.toLowerCase().split(/\W+/)
var positions = new Array()
var word_counts = new Array()
for (var i=0; i<words.length; i++) {
var word = words[i]
if (!word) {
continue
}
if (typeof positions[word] == 'undefined') {
positions[word] = word_counts.length
word_counts.push([word, 1])
} else {
word_counts[positions[word]][1]++
}
}
// Put most frequent words at the beginning.
word_counts.sort(function (a, b) {return b[1] - a[1]})
// Return the first n items
return word_counts.slice(0, n)
}
// Let's see if it works.
var text = "Words in here are repeated. Are repeated, repeated!"
alert(top_words(text, 3))
The result of the example is: [['repeated',3], ['are',2], ['words', 1]]
I would do exactly what you have mentioned above to isolate each word. I would then probably add each word as the index of an array with the number of occurrences as the value.
For example:
var a = new Array;
a[word] = a[word]?a[word]+1:1;
Now you know how many unique words there are (a.length) and how many occurrences of each word existed (a[word]).

Categories

Resources