Counting unique words in strings - javascript
Below I am trying to give string arrays to a function that adds unique words to a words array, and if the word is already in the array to increase the count of the corresponding element in the count array:
var words = [];
var counts = [];
calculate([a, b]);
calculate([a, c]);
function calculate(result) {
for (var i = 0; i < result.length; i++) {
var check = 0;
for (var j = 0; i < tags.length; i++) {
if (result[i] == tags[j]) {
check = 1;
counts[i] = counts[i] + 20;
}
}
if (check == 0) {
tags.push(result[i]);
counts.push(20);
}
check = 0;
}
}
However the output turns out like this:
words = a, b
count = 2, 1
When I expect it to be:
words = a,b,c
count = 2,1,1
Thanks for any help in advance
Breaking the problem down into methods with good names helps you to work out your logic.
Try this:
<script type="text/javascript">
var words = [];
var counts = [];
calculate(["a", "b"]);
calculate(["a", "c"]);
console.log(words);
console.log(counts);
function calculate(result) {
for (var i=0; i<result.length; i++) {
if (array_contains(words, result[i])) {
counts[result[i]]++;
} else {
words.push(result[i]);
counts[result[i]] = 1;
}
}
}
function array_contains(array, value) {
for (var i=0; i<array.length; i++)
if (array[i] == value)
return true;
return false;
}
</script>
Output:
["a", "b", "c"]
[]
a 2
b 1
c 1
Please check this :
you can test it on : http://jsfiddle.net/knqz6ftw/
var words = [];
var counts = [];
calculate(['a', 'b']);
calculate(['a', 'c']);
calculate(['a', 'b', 'c']);
function calculate(inputs) {
for (var i = 0; i < inputs.length; i++) {
var isExist = false;
for (var j = 0; j < words.length; j++) {
if (inputs[i] == words[j]) {
isExist = true
counts[i] = counts[i] + 1;
}
}
if (!isExist) {
words.push(inputs[i]);
counts.push(1);
}
isExist = false;
}
}
console.log(words);
console.log(counts);
Output is :
["a", "b", "c"] (index):46
[3, 2, 2]
A few things were wrong, here's working code:
var words = [];
var counts = [];
calculate(["a", "b"]);
calculate(["a", "c"]);
function calculate(result) {
for (var i = 0; i < result.length; i++) {
var check = 0;
for (var j = 0; j < words.length; j++) {
if (result[i] == words[j]) {
check = 1;
++counts[j];
}
}
if (check == 0) {
words.push(result[i]);
counts.push(1);
}
check = 0;
}
}
Jsbin : http://jsbin.com/hawaco/2/edit?js,console
Things I've changed:
Changed array literal to supply strings instead of variable names: [a,b] to ["a","b"]
Replaced instances of tags (presumably an old name) with words
Changed the 20s to 1s
Made the increment of counts[j] more clear
Fixed use of i/j indices
Things to consider:
Perhaps make this a dictionary rather than a pair of arrays: {"a":1, "b":2}, which would make for simpler code
Pass in the names of the arrays to permit other accumulators, or combine the method and arrays into a single object
Simplified:
var seen = {};
count(["a", "b"], seen);
count(["a", "c"], seen);
function count(words, accumulator) {
for (var i = 0; i < words.length; ++i) {
if(!accumulator.hasOwnProperty(words[i])) {
accumulator[words[i]] = 1;
} else {
++accumulator[words[i]];
}
}
}
Result:
>> seen
[object Object] {
a: 2,
b: 1,
c: 1
}
JSBin: http://jsbin.com/halak/1/edit?js,console
Here's my solution (using an object):
const checkWord = (str) => {
let collection = {};
// split the string into an array
let words = str.split(' ');
words.forEach((word) => {
collection[word] = word;
});
// loop again to check against the array and assign a count
for (let j = 0; j < words.length; j++) {
if (words[j] === collection[words[j]]) {
collection[words[j]] = 0;
}
collection[words[j]]++
}
console.log(collection);
};
You can also use reduce:
const checkWord = (str) => {
let collection = {};
let words = str.split(' ');
words.forEach((word) => {
collection[word] = word;
});
for (var i = 0; i < words.length; i++) {
if (words[i] === collection[words[i]]) {
collection[words[i]] = 0;
}
}
let total = words.reduce((occurrences, word) => {
collection[word]++
return collection;
}, 0);
console.log(total);
};
Related
Find the index of the sub-array that does not contain a number
var array = [[2,3,4],[4,5,6],[2,3,9],[7,8,1]]; var number = 3; If I have this nested array and this variable how do I return the index of the sub-arrays where the number is present. So the final result should be 1 and 3.
Try: array.reduce((acc, subArr, i) => { if (!subArr.includes(number)) { acc.push(i); } return acc; }, [])
The solution using Array.prototype.forEach() and Array.prototype.indexOf() functions: var arr = [[2,3,4],[4,5,6],[2,3,9],[7,8,1]], number = 3, result = []; arr.forEach(function(v,i){ if (v.indexOf(number) === -1) result.push(i); }); console.log(result);
function X(a){ var r = []; for(var i = o ; i < a.length; i++) for(var j = o ; j < a[i].length; i++) if(a[i][j] === number) r.push(i); return r; } i think this should do it. i have just written it here so might have some syntax errors
Since the question is super inconsistent, if you want the index of the subarrays that do have the number, do this: var foundIndices = []; for(var y = 0;y < array.length; y++) { for(var x = 0;x < array[y].length; x++) { if(array[y][x] == number) { foundIndices[foundIndices.length] = y; } } } Otherwise, do this: var foundIndices = []; var found = false; for(var y = 0;y < array.length; y++) { found = false; for(var x = 0;x < array[y].length; x++) { if(array[y][x] == number) { found = true; } } if(found == false) { foundIndices[foundIndices.length] = y; } }
Creating a function to combine a nested array without recursion
I have the following array as an example; let arr = [['red','blue','pink],['dog','cat','bird'],['loud', 'quiet']] I need to write a generalized function that prints all combinations of one word from the first vector, one word from the second vector, etc. I looked up some codes on here but they are all recursion or working only with the specific array. How can I write this code without recursion? let allComb = function(arr) { if (arr.length == 1) { return arr[0]; } else { let result = []; let arrComb = allComb(arr.slice(1)); for (let i = 0; i < arrComb.length; i++) { for (let j = 0; j < arr[0].length; j++) { result.push(arr[0][j] + ' ' + arrComb[i]); } } return result; } } allComb(arr)
This version uses a single increment per cycle technique with no recursion. let arr = [ ['red', 'blue', 'pink'], ['dog', 'cat', 'bird'], ['loud', 'quiet'] ]; function allComb(arr) { var total = 1; var current = []; var result = []; for (var j = 0; j < arr.length; j++) { total *= arr[j].length; current[j] = 0; } for (var i = 0; i < total; i++) { var inc = 1; result[i] = ""; for (var j = 0; j < arr.length; j++) { result[i] += arr[j][current[j]] + ' '; if ((current[j] += inc) == arr[j].length) current[j] = 0; else inc = 0; } } return (result); } console.log(allComb(arr));
You may do as follows; var arr = [['red','blue','pink'],['dog','cat','bird'],['loud', 'quiet']], res = arr.reduce((p,c) => p.reduce((r,x) => r.concat(c.map(y => x + " " + y)),[])); console.log(res);
How to get all possible combinations of elements in an array including order and lengths
function getAllCombinations(arr) { var f = function(arr) { var result = []; var temp = []; for (var i = 0; i < arr.length; i++) { temp = []; temp.push(arr[i]); result.push(temp); for (var j = 0; j < arr.length; j++) { if (j != i) { temp = []; temp.push(arr[i]); temp.push(arr[j]); result.push(temp); for (var k = 0; k < arr.length; k++) { if (k != i && k != j) { temp = []; temp.push(arr[i]); temp.push(arr[j]); temp.push(arr[k]); result.push(temp); for (var l = 0; l < arr.length; l++) { if (l != i && l != j && l != k) { temp = []; temp.push(arr[i]); temp.push(arr[j]); temp.push(arr[k]); temp.push(arr[l]); result.push(temp); } } } } } } } return result; } return f(arr); } //call this function console.log(getAllCombinations(["a", "b", "c", "d"])); [["a"],["a","b"],["a","b","c"],["a","b","c","d"],["a","b","d"],["a","b","d","c"],["a","c"],["a","c","b"],["a","c","b","d"],["a","c","d"],["a","c","d","b"],["a","d"],["a","d","b"],["a","d","b","c"],["a","d","c"],["a","d","c","b"],["b"],["b","a"],["b","a","c"],["b","a","c","d"],["b","a","d"],["b","a","d","c"],["b","c"],["b","c","a"],["b","c","a","d"],["b","c","d"],["b","c","d","a"],["b","d"],["b","d","a"],["b","d","a","c"],["b","d","c"],["b","d","c","a"],["c"],["c","a"],["c","a","b"],["c","a","b","d"],["c","a","d"],["c","a","d","b"],["c","b"],["c","b","a"],["c","b","a","d"],["c","b","d"],["c","b","d","a"],["c","d"],["c","d","a"],["c","d","a","b"],["c","d","b"],["c","d","b","a"],["d"],["d","a"],["d","a","b"],["d","a","b","c"],["d","a","c"],["d","a","c","b"],["d","b"],["d","b","a"],["d","b","a","c"],["d","b","c"],["d","b","c","a"],["d","c"],["d","c","a"],["d","c","a","b"],["d","c","b"],["d","c","b","a"]] A total of 64 combinations for a 4 length array. The function works fine but I need to make this function recursive. The for loops have to be nested based on the length of the array and the push also increased per nested loop. Really appreciate some advice.
Finally made it recursive !! Tried to work down on the the original code posted above moving each loop functionality into simple functions. function getAllCombinations(inputArray) { var resultArray = []; var combine = function() { for (var i in inputArray) { var temp = []; var tempResult = []; for (var j in arguments) { tempResult.push(inputArray[arguments[j]]); if (arguments[j] == i) { temp = false; } else if (temp) { temp.push(arguments[j]); } } if (temp) { temp.push(i); combine.apply(null, temp); } } if (tempResult.length > 0) { resultArray.push(tempResult); } return resultArray; }; return combine(); } See the older version here. Result produces 64 unique combinations for a 4 dimensional array console.log(getAllCombinations(["a", "b", "c", "d"])); [["a","b","c","d"],["a","b","c"],["a","b","d","c"],["a","b","d"],["a","b"],["a","c","b","d"],["a","c","b"],["a","c","d","b"],["a","c","d"],["a","c"],["a","d","b","c"],["a","d","b"],["a","d","c","b"],["a","d","c"],["a","d"],["a"],["b","a","c","d"],["b","a","c"],["b","a","d","c"],["b","a","d"],["b","a"],["b","c","a","d"],["b","c","a"],["b","c","d","a"],["b","c","d"],["b","c"],["b","d","a","c"],["b","d","a"],["b","d","c","a"],["b","d","c"],["b","d"],["b"],["c","a","b","d"],["c","a","b"],["c","a","d","b"],["c","a","d"],["c","a"],["c","b","a","d"],["c","b","a"],["c","b","d","a"],["c","b","d"],["c","b"],["c","d","a","b"],["c","d","a"],["c","d","b","a"],["c","d","b"],["c","d"],["c"],["d","a","b","c"],["d","a","b"],["d","a","c","b"],["d","a","c"],["d","a"],["d","b","a","c"],["d","b","a"],["d","b","c","a"],["d","b","c"],["d","b"],["d","c","a","b"],["d","c","a"],["d","c","b","a"],["d","c","b"],["d","c"],["d"]]
Here is my solution using a subroutine, and closures. Also slice is very useful here. If you found this helpful, or if you think other people will find this helpful, don't be afraid to upvote. function getMyCombinations(coll) { const result = []; (function search(currentPerm, letters) { if (letters.length === 0) return result.push(currentPerm); let trimArray = letters.slice(1); letters.forEach(letter => search(currentPerm + letter, trimArray)); })('', coll) return result; } console.log(getMyCombinations(["a", "b", "c", "d"])); I have refactored my original answer to better align with the users request. function findPerm(array, currentPerm = '', result =[]) { if (array.length === 0) return result; let trimArray = array.slice(1); array.forEach(v => { let copy = [...result]; let perm = (currentPerm + v).split(''); let res = copy.push(perm); result = findPerm(trimArray, currentPerm + v, copy); }); return result; }; console.log(findPerm(['a', 'b', 'c', 'd']));
An alternative solution, seems getting the desired output :) console.log(JSON.stringify(getMyCombinations(["a", "b", "c", "d"]))) function getMyCombinations(arry) { var len = arry.length; var tempArray = []; var result = [] var tempCount = 1; var createCombinations = function(count){ var singleLevelArray = []; arry.forEach(function(item){ if(count){//1 if(count > 1){ for(var j = 0; j < tempArray.length; j++){ if(tempArray[j].indexOf(item) === -1){ var x = tempArray[j].slice(); x.push(item); singleLevelArray.push(x); result.push(x); } } } else { for(var k = 0; k < len; k++){ if(item.indexOf(arry[k]) === -1){ tempArray.push([item, arry[k]]); result.push([item, arry[k]]); } } } } else { result.push([item]); } }) if(singleLevelArray.length){ tempArray = [] tempArray = singleLevelArray; } if(tempCount < len){ createCombinations(tempCount++); } return result; } return createCombinations() }
removing characters from a string - javascript algorithm
I'm practicing algorithm problems and am trying to remove given letters from a string in o(n) time. My attempt below is wrong in a couple of ways: the last index in the outputString array is "undefined" and I'm not sure why. my output is the right letter, but it's being returned for the length of the original string. How can I fix these and why are these errors occurring? function removeChars(lettersToDelete, string) { var flags = {}; // a hash of letters to delete. var outputString = string.split(""); var lettersToDelete = lettersToDelete.split(""); var i, j; for (i = 0; i < lettersToDelete.length; i++) { flags[lettersToDelete[i]] = true; } console.log(flags); for (var j = 0; j < string.length; j++) { if (flags[string[j]]) { outputString[j++] = string[j]; } } console.log(outputString); //[ 'a', 'a', 'a', 'a', undefined ] return outputString.join(""); // 'aaaa' }
function removeChars(lettersToDelete, string) { var flags = {}; // a hash of letters to delete. var outputString = []; //string.split(""); var lettersToDelete = lettersToDelete.split(""); var i, j; for (i = 0; i < lettersToDelete.length; i++) { flags[lettersToDelete[i]] = true; } for (var j = 0; j < string.length; j++) { if (!flags[string[j]]) { outputString.push( string[j] ); } } console.log(outputString); return outputString.join(""); // 'aaaa' } removeChars("itu", "mitul");
Comparing and Filtering two arrays
I've been trying to implement a function where given with two arrays, array1's elements is used as conditions to filter out elements in array2. For instance: array1= [apple, grapes, oranges] array2= [potato, pears, grapes, berries, apples, oranges] After feeding into a function, array2 should have elements as such: filter_twoArrays(array1,array2) array2= [grapes, apples, oranges] I've tried the following code, using for loops and array.splice(), but the problem I am seeing is that when I use the splice method, it seems that it changes the lengths of array2 in the for loop: function filter_twoArrays(filter,result){ for(i=0; i< filter.length; i++){ for(j=0; j< result.length; j++){ if(filter[i] !== result[j]){ result.splice(j,1) } } } Any inputs will be greatly appreciated on how to refine the filter function cheers!
You can use filter as follow var array1 = ['apples', 'grapes', 'oranges', 'banana'], array2 = ['potato', 'pears', 'grapes', 'berries', 'apples', 'oranges']; var intersection = array1.filter(function(e) { return array2.indexOf(e) > -1; }); console.log(intersection); You can also add this method on Array prototype and call it directly on array Array.prototype.intersection = function(arr) { return this.filter(function(e) { return arr.indexOf(e) > -1; }); }; var array1 = ['apples', 'grapes', 'oranges', 'banana'], array2 = ['potato', 'pears', 'grapes', 'berries', 'apples', 'oranges']; var intersection = array1.intersection(array2); console.log(intersection);
You can use some, like this: let newArray = array2.filter( (array22) => !array1.some((array11) => array11.id === array22._id));
Hi this is a porting of the function array_intersect php. Should be good for you http://phpjs.org/functions/array_intersect/ function array_intersect(arr1) { // discuss at: http://phpjs.org/functions/array_intersect/ // original by: Brett Zamir (http://brett-zamir.me) // note: These only output associative arrays (would need to be // note: all numeric and counting from zero to be numeric) // example 1: $array1 = {'a' : 'green', 0:'red', 1: 'blue'}; // example 1: $array2 = {'b' : 'green', 0:'yellow', 1:'red'}; // example 1: $array3 = ['green', 'red']; // example 1: $result = array_intersect($array1, $array2, $array3); // returns 1: {0: 'red', a: 'green'} var retArr = {}, argl = arguments.length, arglm1 = argl - 1, k1 = '', arr = {}, i = 0, k = ''; arr1keys: for (k1 in arr1) { arrs: for (i = 1; i < argl; i++) { arr = arguments[i]; for (k in arr) { if (arr[k] === arr1[k1]) { if (i === arglm1) { retArr[k1] = arr1[k1]; } // If the innermost loop always leads at least once to an equal value, continue the loop until done continue arrs; } } // If it reaches here, it wasn't found in at least one array, so try next value continue arr1keys; } } return retArr; }
You can use const arr1 = [1, 2, 3]; const arr2 = [2, 3]; arr1.filter(e => arr2.indexOf(e) > -1 ? false : true); // [1]
Came here some week back to find a solution to a problem like this but its a pity I couldn't get what I wanted, but now I figured it out in a more simple way. using the arrow function, .filter() method and .includes() method. Declare an arrow function that takes in two arguments: const filterTwoArrays = (string1, string2) => string1.filter(item => string2.includes(item)); console.log(filterTwoArrays(array1, array2)).
Here is one simple way based on your code function array_filter(filter, result) { var filterLen = filter.length; var resultLen = result.length; for (i = 0; i < resultLen; i++) { for (j = 0; j < filterLen; j++) { if (!contains(filter, result[i])) result.splice(i, 1); } } } //Return boolean depending if array 'a' contains item 'obj' function contains(array, value) { for (var i = 0; i < array.length; i++) { if (array[i] == value) { return true; } } return false; }
Since you have tagged javascript here is the solution. function f1(x, y) { var t = y.slice(0); var r = []; for (var i = 0; i < x.length; i++) { for (var j = 0; j < y.length; j++) { if (x[i] === y[j]) { [].push.apply(r, t.splice(j, 1)); } } } console.log(r) y.length = 0; [].push.apply(y, r); }
Mark the items which are to be filtered out via delete result[index] manipulate them as needed. JavaScript window.onload = runs; function runs() { var array1 = ["apples", "grapes", "oranges"]; var array2 = ["potato", "pears", "grapes", "berries", "apples", "oranges"]; var result = filter_twoArrays(array1, array2); function filter_twoArrays(filter, result) { var i = 0, j = 0; for (i = 0; i < result.length; i++) { var FLAG = 0; for (j = 0; j < filter.length; j++) { if (filter[j] == result[i]) { FLAG = 1; } } if (FLAG == 0) delete result[i]; } return result; } var body = document.getElementsByTagName("body")[0]; var i = 0; for (i = 0; i < result.length; i++) { if (result[i] !== undefined) body.innerHTML = body.innerHTML + result[i] + " "; } }
const func = array1.filter(item => array2.includes(item));