I'm trying to make a simple 'bad words' filter with javascript. It's meant to listen to any submit events on the page, then iterate through all input fields of the text type, check them for bad stuff by comparing the entered text with the word list, and finally return an according console.log/alert (for now).
I have two files: word-list.js with the critical words (loads first) and filter.js which pulls an array with all words from word-list.js.
My problems is, swear_words_arr[1] is 'undefined' and I don't understand why. I've been looking around for solutions, but still I can't seem to determine the reason for this. Help is much appreciated.
// get all inputs type = text and turn html collection into array
var getInputs = document.querySelectorAll("input[type=text]")
var inputs = Array.from(getInputs);
//var swear_alert_arr -> from in word-list.js
var swear_alert_arr = new Array();
var swear_alert_count = 0;
function reset_alert_count() {
swear_alert_count = 0;
}
function validate_text() {
reset_alert_count();
inputs.forEach(function(input) {
var compare_text = input.value;
console.log(compare_text);
for (var i = 0; i < swear_words_arr.length; i++) {
for (var j = 0; j < compare_text.length; i++) {
if (
swear_words_arr[i] ==
compare_text.substring(j, j + swear_words_arr[i].length).toLowerCase()
) {
swear_alert_arr[swear_alert_count] =
compare_text.substring(
j,
j + swear_words_arr[i].length
);
swear_alert_count++;
}
}
}
var alert_text = "";
for (var k = 1; k <= swear_alert_count; k++) {
alert_text += "\n" + "(" + k + ") " + swear_alert_arr[k - 1];
if (swear_alert_count > 0) {
alert("No!");
console.log('omg no bad stuff! D:');
} else {
console.log('no bad stuff found :)');
}
}
});
}
window.onload = reset_alert_count;
window.addEventListener('submit', function() {
validate_text();
});
It doesn't look like you've declared the array you're trying to access.
But, instead of loops with nested loops and keeping track of loop counters, just get a new array that contains any bad words in the submitted array. You can do this a number of ways, but the Array.prototype.filter() method works nicely:
let badWords = ["worse", "terrible", "horrible", "bad"];
let submittedWords = ["Good", "Terrible", "Great", "Fabulous", "Bad", "OK"];
// Loop over the submitted words and return an array of all the bad words found within it
let bad = submittedWords.filter(function(word){
// Do a case-insensitive match test. Return the word from the submitted words
// if it's on the bad word list.
return badWords.indexOf(word.toLowerCase()) > -1 ? word: null;
});
console.log("Bad words found in submitted data: " + bad.join(", "));
I have a live search autocomplete filter that I'm using to weed out a directory of people. Using this search, I want people to be able to search using multiple words, which will further reduce the number of results they get.
Currently, with the code below, if someone searches "technician Atlanta", they will get the directoryprofile divs that contain "technician" and the ones that contain "Atlanta". What I want is for it to find a div that contains BOTH of those words...so they can find a technician that is in Atlanta. Hopefully that makes sense.
My code is working for including the terms separately, but I want them to find rows containing multiple terms. Any ideas? THANKS in advance!!
$("#filter").keyup(function () {
// Split the current value of the filter textbox
var data = this.value.split(" ");
// Get the table rows
var rows = $(".directoryprofile");
if (this.value == "") {
rows.show();
return;
}
// Hide all the rows initially
rows.hide();
// Filter the rows; check each term in data
rows.filter(function (i, v) {
for (var d = 0; d < data.length; ++d) {
if ($(this).is(":contains('" + data[d] + "')")) {
return true;
}
}
return false;
})
// Show the rows that match.
.show();
});
rows.filter(function(i, v) {
var truth = true;
for (var d = 0; d < data.length; ++d) {
//remain true so long as all of the filters are found
//if even one is not found, it will stay false
truth = truth && $(this).is(":contains('" + data[d] + "')");
}
return truth;
})
//OR you could just flip your logic and return false if any of the
//filters are not found
rows.filter(function(i, v) {
for (var d = 0; d < data.length; ++d) {
if (!$(this).is(":contains('" + data[d] + "')")) {
return false;
}
}
return true;
})
I am trying to write a function which finds all unique characters in a provided string.
I'd like the function to return the results in the following format:
removeDuplicates('th#elex_ash?') -> {unique: 'aehlstx', duplicates: 2}
So far I have come up with the following attempted solution:
function removeDuplicates(str){
var unique ="";
for (var i=0; i<str.length; i++){
if(unique.indexOf(str[i]) == -1){
unique += str[i];
}
}
unique = unique.replace(/[&\/\\#,_+()$~%.'":*?<>]/g, '');
return unique.split('').sort().join('');
}
console.log(removeDuplicates('aaabbbac'));
console.log(removeDuplicates('a'));
console.log(removeDuplicates('th#elex_ash?'));
If you are writing for an environment where you can use newer javascript features. Set makes this a little easier since it will enforce uniqueness among the contents. You can also compare the lengths of the cleaned string with the uniques to find the duplicate count
For example:
function removeDuplicates(str){
str = str.replace(/[&\/\\#,_+()$~%.'":*?<>]/g, '')
let unique = Array.from(new Set(str))
.sort((a, b) => a.localeCompare(b))
.join('')
let duplicates = str.length - unique.length
return {unique, duplicates}
}
console.log(removeDuplicates("th#elex_ash?"))
function removeDuplicates(str) {
var returnObject = {
unique : "",
duplicates : 0
};
for (var i = 0; i < str.length; i++){
if (returnObject.unique.indexOf(str[i]) < 0) {
returnObject.unique += str[i];
} else {
returnObject.duplicates++;
}
}
returnObject.unique = returnObject.unique.replace(/[&\/\\#,_+()$~%.'":*?<>]/g, '');
returnObject.unique = returnObject.unique.split('').sort().join('');
return returnObject;
}
console.log(removeDuplicates('aaabbbac'));
console.log(removeDuplicates('a'));
console.log(removeDuplicates('th#elex_ash?'));
You are very close!
An object can be returned in Javascript just like anything else; for instance, to return the format you were asking for, simply do the following:
return {
unique: unique,
duplicates: duplicates
}
Notice how your variable names are the same as your property keys? You can use a shorthand notation by simply writing unique and duplicates, rather than unique: unique and duplicates: duplicates.
You're not keeping a count of duplicates. To do so, simply add an else block to your if(unique.indexOf(str[i]) == -1) conditional, which should only be reached when a character is indeed a duplicate, and increment a counter - lets name it duplicates.
Complete Solution
function removeDuplicates(str) {
var unique = "";
var duplicates = 0;
for (var i = 0; i < str.length; i++) {
if (unique.indexOf(str[i]) == -1) {
unique += str[i];
} else {
duplicates++;
}
}
unique = unique.replace(/[&\/\\#,_+()$~%.'":*?<>]/g, '').split('').sort().join('')
return {
unique,
duplicates
}
}
const testString = 'th#elex_ash?';
const expectedOutput = {
unique: 'aehlstx',
duplicates: 2
};
console.log(removeDuplicates(testString));
The function finds which tv character the user compares to based on their answers to my questions. My code now is very inefficient for multiple select menus!!! Maybe an object that takes all selectmenus in html and allows me to assign array values based on the selected index of a selectmenu.
function onSelectMenuBlur() {
"use strict";
/*list of arrays that will be added to when the user selects an option in a selectmenu.*/
var rickArray = [];
var shaneArray = [];
var bobArray = [];
var carolArray = [];
var lArray = [];
var sm = document.getElementById("selectmenu");
.onchange function that determines what array will be added to depending on the option selected in the select menu. This function will add an array value of 1 once to an array. Seems like an inefficient way, especially with multiple selectmenus!
sm.onchange = function() {
if(sm.selectedIndex + 1 === 1) {
rickArray.push(1);
shaneArray.pop();
bobArray.pop();
carolArray.pop();
lArray.pop();
alert(rickArray.length);
}
else if(sm.selectedIndex + 1 === 2) {
shaneArray.push(1);
rickArray.pop();
bobArray.pop();
carolArray.pop();
lArray.pop();
alert(shaneArray.length);
}
else if(sm.selectedIndex + 1 === 3) {
bobArray.push(1);
rickArray.pop();
shaneArray.pop();
carolArray.pop();
lArray.pop();
alert(bobArray.length);
}
else if(sm.selectedIndex + 1 === 4) {
carolArray.push(1);
rickArray.pop();
shaneArray.pop();
bobArray.pop();
lArray.pop();
alert(carolArray.length);
}
else if(sm.selectedIndex + 1 === 5) {
lArray.push(1);
rickArray.pop();
shaneArray.pop();
bobArray.pop();
carolArray.pop();
alert(lArray.length);
}
else{}
};
.onblur purpose to find array with biggest length or value out of all selectmenus to determine which person associated with the array the user is like. Again seems like an inefficient way to handle!
sm.onblur = function() {
var rickL = rickArray.length;
var shaneL = shaneArray.length;
var bobL = bobArray.length;
var carolL = carolArray.length;
var lL = lArray.length;
// unfinished if else statement !!
if(rickL > shaneL && rickL > bobL && rickL > carolL && rickL > lL) {
alert("you are Rick Grimes");
}
else{
alert("you are someone else");
}
};
}
Use a 2-dimensional array instead of separate arrays for each character, and then use the selected index as an index into the array.
var characters = [[], [], [], [], []];
sm.onchange = function() {
for (var i = 0; i < characters.length; i++) {
if (i == this.selectedIndex) {
characters[i].push(1);
alert(characters[i].length);
} else {
characters[i].pop();
}
}
};
To get the character names in there, make it an array of objects.
characters = [
{ name: "Rick",
array: []
},
{ name: "Carol",
array: []
},
...
}
Then you would use characters[i].array.push(1). And then when you want to say which character they are, find the object with the longest array and then print its .name.
I have an array which looks like this:
["1,8", "4,6,8", "8,9", "6,9"]
1/ I would like to turn it in to this
[1,8,4,6,8,8,9,6,9]
2/ I would then like to find matching values, by looking for the most number:
[8]
This first has been solved with this:
var carArray = ["1,8", "4,6,8,7,7,7,7", "8,9", "6,9"];
//1) create single array
var arr = carArray.join().split(',');
//2) find most occurring
var counts = {}; //object to hold count for each occurence
var max = 0, maxOccurring;
arr.forEach(function(el){
var cnt = (counts[el] || 0); //previous count
counts[el] = ++cnt;
if(cnt > max && cnt > 1){ //only register if more than once (cnt>1)
max=cnt;
maxOccurring = el;
}
});
if(maxOccurring){
//there was an element more than once, maxOccuring contains that element
setResult('Most occuring: ' + maxOccurring + ' (' + max + ' times)');
}
else{
//3)/4) ???
setResult('sorting?');
}
//below is only for test display purposes
function setResult(res){
console.log(res);
}
3/ If the are no matching values like this
[1,8,4,6,5,7]
4/ Then I need to compare this array to another array, such as this
[6,7,4,1,2,8,9,5]
If the first number in <4> array above appears in <3> array, then get that number, ie in the above example I need to get 6. The <4> array will be static values and not change. The numbers is <3> will be dynamic.
EDIT Not the most elegant of answers, but I do have something working now. I didn't compare the original array directly with the second array, instead used simple if/else statements to do what I needed:
var carArray = ["1,5", "4", "8,2", "3,9,1,1,1"];
//1) create single array
var arr = carArray.join().split(',');
//2) find most occurring
var counts = {}; //object to hold count for each occurence
var max = 0, maxOccurring;
arr.forEach(function(el){
var cnt = (counts[el] || 0); //previous count
counts[el] = ++cnt;
if(cnt > max && cnt > 1){ //only register if more than once (cnt>1)
max=cnt;
maxOccurring = el;
}
});
if(maxOccurring){
//there was an element more than once, maxOccuring contains that element
console.log('Most occuring: ' + maxOccurring + ' (' + max + ' times)');
console.log(maxOccurring);
}
else {
// If not occuring, match from a list
if(jQuery.inArray("6", arr) !== -1) { console.log('6'); }
else if(jQuery.inArray("9", arr) !== -1) { console.log('9'); }
else if(jQuery.inArray("7", arr) !== -1) { console.log('7'); }
else if(jQuery.inArray("5", arr) !== -1) { console.log('5'); }
else if(jQuery.inArray("4", arr) !== -1) { console.log('4'); }
else if(jQuery.inArray("1", arr) !== -1) { console.log('1'); }
else { console.log('not found'); }
}
Example Fiddle
Step 1 is fairly easy by using javascript's join and split methods respectively:
var arr = carArray .join().split(',');
For step 2, several methods can be used, the most common one using an object and using the elements themselves as properties. Since you only need to get the most occurring value if there is a reoccurring value, it can be used in the same loop:
var counts = {}; //object to hold count for each occurence
var max = 0, maxOccurring;
arr.forEach(function(el){
var cnt = (counts[el] || 0); //previous count
counts[el] = ++cnt;
if(cnt > max && cnt > 1){ //only register if more than once (cnt>1)
max=cnt;
maxOccurring = el;
}
});
After the above, the variable maxOccurring will contain the reoccurring value (if any) and max will contain the times it occured
For step 4 the easiest way is to loop through the compare array and get the element that occurs in the input array:
var cmpArr = ['6','7','4','1','2','8','9','5'];
//find the first occurrence inside the cmpArr
res = function(){ for(var i= 0 ; i < cmpArr.length; i++){ if(arr.indexOf(cmpArr[i]) !== -1)return cmpArr[i];}}();
The above uses an in place function which is called immediately to be able to use return. You could also just use a loop and assign res when found, then break from the loop.
Last update, an alternate fiddle where the above is converted to a single function: http://jsfiddle.net/v9hhsdny/5/
Well first of all the following code results in four matching answers since the jQuery selectors are the same.
var questionAnswer1 = $(this).find('input[name=questionText]').val();
var questionAnswer2 = $(this).find('input[name=questionText]').val();
var questionAnswer3 = $(this).find('input[name=questionText]').val();
var questionAnswer4 = $(this).find('input[name=questionText]').val();
var carArray = [questionAnswer1, questionAnswer2, questionAnswer3, questionAnswer4];
You could use the eq(index) method of jQuery to select the appropriate element. However having 4 inputs with the same name is a bad practice.
Well lets say that the carArray has 4 different values which all consist out of comma separated numbers. You could then do the following:
var newArr = [];
carArray.forEach(function(e) {
e.split(",").forEach(function(n) {
newArr.push(n);
});
});
Well then we got to find the most occurring number. JavaScript doesn't have any functions for that so we will have to find an algorithm for that. I found the following algorithm on this stackoverflow page
var count = function(ary, classifier) {
return ary.reduce(function(counter, item) {
var p = (classifier || String)(item);
counter[p] = counter.hasOwnProperty(p) ? counter[p] + 1 : 1;
return counter;
}, {})
}
var occurances = count(newArr);
It isn't clear to me what you're trying to do in step 3 and 4, so can't answer those at the moment.
var ary = ["1,8", "4,6,8", "8,9", "6,9"];
var splitted = ary.reduce(function(acc, item) {
return acc.concat(item.split(','));
}, []);
var occurences = splitted.reduce(function(acc, item) {
if (!acc.hasOwnProperty(item)) acc[item] = 0;
acc[item] += 1;
return acc;
},{}),
biggest = Object.keys(occurences).reduce(function (acc, key) {
if (occurences[key] > acc.occurences) {
acc.name = key;
acc.occurences = occurences[key];
}
return acc;
},{'name':'none','occurences':0}).name;
var vals=["1,8", "4,6,8", "8,9", "6,9"];
// 1) turn into number array
var arrNew=[];
for(var i=0; i<vals.length; i++)
{
arrLine=vals[i].split(",");
for (var j=0;j<arrLine.length;j++) { arrNew.push (parseInt(arrLine[j])) }
}
//result:
alert(arrNew.join(";");
// 2) find most common
var found=[];
for(var i=0; i<arrNew.length; i++) {
// make an array of the number of occurrances of each value
if (found["num"+newArray[i]]) {
found["num"+newArray[i]] ++ ;
} else {
found["num"+newArray[i]]=1;
}
}
var mostCommon={count:0,val:"ROGUE"};
for (x in found) {
if (found[x] > mostCommon.count) {
mostCommon.count=found[x].count;
mostCommon.val=x;
}
}
// result :
alert(mostCommon.val);
//3) not quite sure what you meant there
// 4) unique values:
// at this point the 'found' list contains unique vals
var arrUnique=[];
for (x in found) {
arrUnique.push[x];
}
// result :
alert(arrUnique.join(";"))
//sort:
arrUnique.sort(function(a, b){return a-b});
(This won't work in most browsers) but on a side note, when ES6 becomes widely supported, your solution could look like this:
var arr1 = ["1,8", "4,6,8", "8,9", "6,9"];
var arr2 = arr1.join().split(',');
var s = Array.from(new Set(arr2)); //Array populated by unique values, ["1", "8", "4", "6", "9"]
Thought you might like to see a glimpse of the future!
1.
var orgArray = ['1,8', '4,6,8', '8,9', '6,9'];
var newArray = [];
for (var i in orgArray) {
var tmpArray = orgArray[i].split(',');
for (var j in tmpArray) {
newArray.push(Number(tmpArray[j]));
}
}
2.
var counts = {};
var most = null;
for (var i in newArray) {
var num = newArray[i];
if (typeof counts[num] === 'undefined') {
counts[num] = 1;
} else {
++(counts[num]);
}
if (most == null || counts[num] > counts[most]) {
most = num;
} else if (most != null && counts[num] === counts[most]) {
most = null;
}
}
I don't understand the question 3 and 4 (what "unique order" means) so I can't answer those questions.