CodeWars/ Merged String Checker - javascript

The challenge is next:
At a job interview, you are challenged to write an algorithm to check if a given string, s, can be formed from two other strings, part1 and part2.
The restriction is that the characters in part1 and part2 are in the same order as in s.
The interviewer gives you the following example and tells you to figure out the rest from the given test cases.
What am I doing wrong? Why it fails anyway?
I wrote 2 different scripts, and both aren't working for some test cases
function isMerge(s, part1, part2) {
var sArr = s.split('');
var part1Arr = part1.split('');
var part2Arr = part2.split('');
var tempArr = new Array(sArr.length);
function compareArrays(arr1, arr2){
var count = 0;
for (var i = 0; i < arr1.length; i++) {
if (arr1[i] !== arr2[i]) count++;
}
return (count == 0);
}
for (var i = 0; i < sArr.length; i++) {
for (var j = 0; j < part1Arr.length; j++) {
if (sArr[i] == part1Arr[j]) tempArr[i] = j;
}
for (var k = 0; k < part2Arr.length; k++) {
if (sArr[i] == part2Arr[k]) tempArr[i] = k;
}
}
alert(tempArr);
var check = tempArr.slice();
check.sort();
alert(check);
if (compareArrays(tempArr, check)) return true;
else return false;
}
alert(isMerge('codewars', 'cdw', 'oears'));
function isMerge(s, part1, part2) {
// create arrays of letters
var sArr = s.split('');
var part1Arr = part1.split('');
var part2Arr = part2.split('');
// create an associative array 'temp' (0:C, 1:O and so on)
var temp = {};
for (var k = 0; k < sArr.length; k++) {
temp[k] = sArr[k];
}
// reverse an associative array 'temp' (now C:0, O:0 and so on)
for (var key in temp) {
var keyTemp = key;
var keyValue = temp[key];
key = keyValue;
temp[key] = keyTemp;
}
// the function that compares arrays
function compareArrays(arr1, arr2){
var count = 0;
for (var i = 0; i < arr1.length; i++) {
if (arr1[i] !== arr2[i]) count++;
}
return (count == 0);
}
// sorting function
function order(a, b) {
var comparingA;
var comparingB;
for (var char in temp) {
if (char == a) {
comparingA = temp[char]; // comparingA is the number of 'a' in object 'temp'
}
if (char == b){
comparingB = temp[char]; // comparingB is the number of 'b' in object 'temp'
}
}
return (comparingA - comparingB);
}
// create copies of arrays
var part1Sorted = part1Arr.slice();
var part2Sorted = part2Arr.slice();
// and sort that copies
part1Sorted.sort(order);
part2Sorted.sort(order);
// If the array did not change after sorting, the order of the letters was correct
if (compareArrays(part1Sorted, part1Arr) && compareArrays(part2Sorted, part2Arr)) {
// so now we can check is merge possible
sArr = sArr.sort();
var parts = part1Arr.concat(part2Arr);
parts = parts.sort();
var res = compareArrays(sArr, parts);
return res;
}
return false;
}
alert(isMerge('codewars', 'code', 'wasr'));
alert(isMerge('codewars', 'oers', 'cdwa'));
I just added comments to the second script

I find it hard to understand what your code is attempting to do. It would help if you provided comments as well as explain the idea behind the algorithm/s you are attempting to implement.
Here's a commented example of a recursion that considers if pointers i and j to parts 1 & 2 could constitute a valid merge up to that point.
function isMerge(s, part1, part2) {
// Merge is invalid if the parts' lengths don't add up to the string's
if (part1.length + part2.length != s.length)
return false;
// Recursive function
function g(i, j){
// Base case: both pointers are exactly at the end of each part
if (i == part1.length && j == part2.length)
return true;
// One of our pointers has extended beyond the part's length,
// that couldn't be right
if (i > part1.length || j > part2.length)
return false;
// Just part1 matches here so increment i
if (part1[i] == s[i + j] && part2[j] != s[i + j])
return g(i + 1, j);
// Just part2 matches here so increment j
else if (part1[i] != s[i + j] && part2[j] == s[i + j])
return g(i, j + 1);
// Both parts match here so try incrementing either pointer
// to see if one of those solutions is correct
else if (part1[i] == s[i + j] && part2[j] == s[i + j])
return g(i + 1, j) || g(i, j + 1);
// Neither part matches here
return false;
}
// Call the recursive function
return g(0,0);
}
console.log(isMerge('codewars', 'cdw', 'oears'));
console.log(isMerge('codecoda', 'coda', 'code'));
console.log(isMerge('codewars', 'oers', 'cdwa'));
console.log(isMerge('codewars', 'cdw', 'years'));
Stack version for really long strings:
function isMerge2(s, part1, part2) {
if (part1.length + part2.length != s.length)
return false;
let stack = [[0,0]];
while (stack.length){
[i, j] = stack.pop();
if (i == part1.length && j == part2.length)
return true;
if (i > part1.length || j > part2.length)
continue;
if (part1[i] == s[i + j] && part2[j] != s[i + j])
stack.push([i + 1, j]);
else if (part1[i] != s[i + j] && part2[j] == s[i + j])
stack.push([i, j + 1]);
else if (part1[i] == s[i + j] && part2[j] == s[i + j]){
stack.push([i + 1, j]);
stack.push([i, j + 1]);
}
}
return false;
}
function test(){
let s = '';
for (let i=0; i<1000000; i++)
s += ['a','b','c','d','e','f','g'][~~(Math.random()*6)];
let lr = {
l: '',
r: ''
};
for (let i=0; i<s.length; i++){
let which = ['l', 'r'][~~(Math.random()*2)];
lr[which] += s[i];
}
console.log(isMerge2(s,lr.l,lr.r));
}
test();

This is a recursive approach: it checks for a match of the first character of the string with either of the parts, and if there's a match recurses to try and match the rest of the string with the rest of the parts. The tricky thing is that when the first character of both parts is the same, you have to check if you can match against either of them (this solves the Bananas test).
function isMerge(str, p1, p2) {
if (!str.length) return !p1.length && !p2.length;
if (p1.length && str.charAt(0) == p1.charAt(0)) {
if (p2.length && str.charAt(0) == p2.charAt(0)) {
return isMerge(str.substr(1), p1.substr(1), p2) || isMerge(str.substr(1), p1, p2.substr(1));
}
else {
return isMerge(str.substr(1), p1.substr(1), p2);
}
}
else if (p2.length && str.charAt(0) == p2.charAt(0)) {
return isMerge(str.substr(1), p1, p2.substr(1));
}
else {
return false;
}
}

Recursive Call:
You could use a recursive approach by first checking the length of string and part strings and then by the length or by checking a character and by checking the rest of the given part strings.
function isMerge(s, part1, part2) {
if (s.length !== part1.length + part2.length) {
return false;
}
if (!s.length) {
return true;
}
if (part1[0] === s[0] && isMerge(s.slice(1), part1.slice(1), part2)) {
return true;
}
if (part2[0] === s[0] && isMerge(s.slice(1), part1, part2.slice(1))) {
return true;
}
return false;
}
console.log(isMerge('codewars', 'cdw', 'oears')); // true
console.log(isMerge('codewars', 'oers', 'cdwa')); // true
console.log(isMerge('codecoda', 'coda', 'code')); // true
console.log(isMerge('baeabb', 'b', 'baeab')); // true
console.log(isMerge('bdab', 'bdab', '')); // true
console.log(isMerge('bfaef', 'f', 'bfae')); // true
console.log(isMerge('codewars', 'cdw', 'years')); // false
console.log(isMerge('codewars', 'code', 'warss')); // false
console.log(isMerge('codewars', 'codes', 'wars')); // false
console.log(isMerge('', 'a', 'b')); // false
.as-console-wrapper { max-height: 100% !important; top: 0; }
With a Stack instead of a Recursive Call:
function isMerge(s, part1, part2) {
var stack = [[s, part1, part2]];
if (s.length !== part1.length + part2.length) {
return false;
}
while (stack.length) {
[s, part1, part2] = stack.shift();
if (!s.length) {
return true;
}
if (part1[0] === s[0]) {
stack.push([s.slice(1), part1.slice(1), part2]);
}
if (part2[0] === s[0]) {
stack.push([s.slice(1), part1, part2.slice(1)]);
}
}
return false;
}
console.log(isMerge('codewars', 'cdw', 'oears')); // true
console.log(isMerge('codewars', 'oers', 'cdwa')); // true
console.log(isMerge('codecoda', 'coda', 'code')); // true
console.log(isMerge('baeabb', 'b', 'baeab')); // true
console.log(isMerge('bdab', 'bdab', '')); // true
console.log(isMerge('bfaef', 'f', 'bfae')); // true
console.log(isMerge('codewars', 'cdw', 'years')); // false
console.log(isMerge('codewars', 'code', 'warss')); // false
console.log(isMerge('codewars', 'codes', 'wars')); // false
console.log(isMerge('', 'a', 'b')); // false
.as-console-wrapper { max-height: 100% !important; top: 0; }

May you try this below?
function isMerge(s, part1, part2) {
var result= true;
var total = part1 + part2;
for (var i = 0; i < s.length; i++) {
var char = s.charAt(i);
if(total.indexOf(char) === -1) {
result = false;
break;
}
}
return result;
}

First of all, here is your code just working:
function isMerge(s, part1, part2) {
var sArr = s.split('');
var part1Arr = part1.split('');
var part2Arr = part2.split('');
var tempArr = new Array(sArr.length);
function compareArrays(arr1, arr2){
var count = 0;
for (var i = 0; i < arr1.length; i++) {
if (arr1[i] != arr2[i]) count++;
}
return (count == 0);
}
for (var i = 0; i < sArr.length; i++) {
for (var j = 0; j < part1Arr.length; j++) {
if (sArr[i] == part1Arr[j]) tempArr[i] = part1Arr[j];
}
for (var k = 0; k < part2Arr.length; k++) {
if (sArr[i] == part2Arr[k]) tempArr[i] = part2Arr[k];
}
}
alert(tempArr);
if (compareArrays(tempArr, sArr)) return true;
else return false;
}
alert(isMerge('codewars', 'cdw', 'oears'));
Now, what was the problem?
for (var j = 0; j < part1Arr.length; j++) {
/* Here you assigned the index (tempArr[i] = j;) not the char */
if (sArr[i] == part1Arr[j]) tempArr[i] = part1Arr[j];
}
for (var k = 0; k < part2Arr.length; k++) {
/* Here you assigned the index (tempArr[i] = k;) not the char */
if (sArr[i] == part2Arr[k]) tempArr[i] = part2Arr[k];
}
Hope i could help you ;)

Simple merge logic:
function isMerge(s, part1, part2) {
var sArr = s.split('');
var part1Arr = part1.split('');
var part2Arr = part2.split('');
var j = 0;
var k = 0;
for (var i = 0; i < sArr.length; i++) {
if ((j < part1Arr.length) && (sArr[i] == part1Arr[j]))
j++
else if ((k < part2Arr.length) && (sArr[i] == part2Arr[k]))
k++
else
break
}
return (j == part1Arr.length && k == part2Arr.length && (j + k) == sArr.length);
}
console.log(isMerge('abcd', 'ac', 'bd'));
console.log(isMerge('abcd', 'acd', 'b'));
console.log(isMerge('abcd', 'ac', 'b'));
console.log(isMerge('abcd', 'ac', 'db'));
console.log(isMerge('abcd', 'c', 'b'));
console.log(isMerge('a', '', 'a'));
console.log(isMerge('', '', ''));
console.log(isMerge('', 'a', 'b'));
console.log(isMerge('ab', '', ''));

Related

JavaScript Elements of array being equal function not working

While taking some online JS tests, I am stuck on why my function for testing if the elements within two arrays are equal is not working. I am using the function to make sure that the new array does not have duplicate values.
The following is my function for testing if the elements of the arrays are equal or not:
const isEqualArr = (a, b) => {
for (let i = 0; i < a.length; i++) {
if (a[i] != b[i]) {
return false;
}
}
return true;
};
I call to the function within a for loop, then I test for undefined, because the first time around, the outputArr is empty
for (let x = 0; x < numsLength; x++) {
if (typeof outputArr[x] != 'undefined') {
if (isEqualArr(tempArr, [outputArr[x]])) {
However, the result shows that there are duplicates:
0: Array [ -1, 0, 1 ]
​
1: Array [ -1, 2, -1 ]
​
2: Array []
​
3: Array [ -1, -1, 2 ]
​
4: Array []
​
5: Array [ 0, 1, -1 ]
​
6: Array [ 0, -1, 1 ]
​
7: Array [ 1, 0, -1 ]
​
8: Array [ -1, 0, 1 ]
The other issue is that not only do I have two null arrays (duplicates), but when I test for null before the push, it is not working either:
if(tempArr != null ) {
outputArr.push(tempArr);
}
I have tried tempArr[0] != null, tempArr[0] != '' as well as
if (typeof tempArr[0] != 'undefined')
But it still inserts null arrays into the outputArr.
The following is the premise of the test:
Given an integer array nums, return all the triplets [nums[i], nums[j], nums[k]] such that i != j, i != k, and j != k, and nums[i] + nums[j] + nums[k] == 0.
Notice that the solution set must not contain duplicate triplets. Given nums = [-1,0,1,2,-1,-4]
The following code is my solution, but the duplicate entries, as well as the null entries, makes this an incorrect solution. If you guys can see why my isEqualArr function is at fault, then I would appreciate it.
const threeSum = (nums) => {
let numsLength = nums.length;
let tempArr = [];
let outputArr = [];
if (numsLength > 3) {
for (let i = 0; i < numsLength; i++) {
for (let j = 1; j < numsLength; j++) {
for (let k = 2; k < numsLength; k++) {
if (
i != j &&
i != k &&
j != k &&
nums[i] + nums[j] + nums[k] == 0
) {
tempArr[0] = nums[i];
tempArr[1] = nums[j];
tempArr[2] = nums[k];
for (let x = 0; x < numsLength; x++) {
if (typeof outputArr[x] != 'undefined') {
if (!isEqualArr(tempArr, [outputArr[x]])) {
if (typeof tempArr[0] != 'undefined') {
outputArr.push(tempArr);
console.log(
'temp: ' + tempArr + ' outputArr: ' + outputArr[x]
);
console.log(
'compare: ' + isEqualArr(tempArr, outputArr[x])
);
console.log(outputArr);
tempArr = [];
}
}
}
}
if (i == 0) {
outputArr.push(tempArr);
tempArr = [];
} else {
// do nothing
}
}
}
}
}
}
return outputArr;
};
const isEqualArr = (a, b) => {
for (let i = 0; i < a.length; i++) {
if (a[i] != b[i]) {
return false;
}
}
return true;
};
EDIT: I was able to eliminate the null entries by moving the code that checks if it is the first time to run above the for loop:
if (i == 0) {
outputArr.push(tempArr);
tempArr = [];
} else {
// do nothing
}
for (let x = 0; x < numsLength; x++) {
if (typeof outputArr[x] != 'undefined') {
if (!isEqualArr(tempArr, [outputArr[x]])) {
if (typeof tempArr[0] != 'undefined') {
outputArr.push(tempArr);
console.log(
'temp: ' + tempArr + ' outputArr: ' + outputArr[x]
);
console.log(
'compare: ' + isEqualArr(tempArr, outputArr[x])
);
console.log(outputArr);
tempArr = [];
}
}
}
}
BTW, another thing that is not working if the following logic:
i != j &&
i != k &&
j != k &&
You can see by the outputArr that this logic is being completely ignored.
REFACTORED: even though the online test marked my solution as wrong, you can see with the results, that it is correct. Especially when you factor in the conditionals for making sure that nums[i] != nums[j] and so forth:
const threeSum = (nums) => {
let numsLength = nums.length;
let tempArr = [];
let outputArr = [];
for (let i = 0; i < numsLength; i++) {
for (let j = 0; j < numsLength; j++) {
for (let k = 0; k < numsLength; k++) {
if (
nums[i] != nums[j] &&
nums[i] != nums[k] &&
nums[j] != nums[k] &&
nums[i] + nums[j] + nums[k] == 0
) {
if (typeof outputArr[0] != 'undefined') {
/**********
* if it reaches this conditional
* then outputArr has at least one element
***********/
if (typeof outputArr[k] != 'undefined') {
tempArr[0] = nums[i];
tempArr[1] = nums[j];
tempArr[2] = nums[k];
if (isEqualArr(tempArr, outputArr)) {
// do nothing because there is already an element within the array
} else {
outputArr.push(tempArr);
// empty tempArr after insert
tempArr = [];
}
}
} else {
// push triplet elements into temp array for the first iteration only
tempArr[0] = nums[i];
tempArr[1] = nums[j];
tempArr[2] = nums[k];
// insert tempArr for the first iteration only
outputArr.push(tempArr);
// empty tempArr after insert
tempArr = [];
}
}
}
}
}
return outputArr;
};
const isEqualArr = (a, b) => {
for (elem in b) {
for (let i = 0; i < a.length; i++) {
if (a[i] != elem[i]) {
// do nothing
} else {
return true;
}
}
}
return false;
};
RESULTS:
(3) [Array(3), Array(3), Array(3)]
0: (3) [-1, 0, 1]
1: (3) [1, 0, -1]
2: (3) [-1, 1, 0]
length: 3
Your inner for loop is confusing, if you replace it by a forEach you can see what's going on, you should pass as argument outputArr[x] not [outputArr[x]] and there's more stuff.
const threeSum = (nums) => {
let numsLength = nums.length;
let tempArr = [];
let outputArr = [];
if(numsLength < 3) return;
for (let i = 0; i < numsLength; i++) {
for (let j = 1; j < numsLength; j++) {
for (let k = 2; k < numsLength; k++) {
if (
i != j &&
i != k &&
j != k &&
nums[i] + nums[j] + nums[k] == 0
) {
tempArr.push(nums[i], nums[j], nums[k]); // push three at the same time, it's cleaner and avoid problems
outputArr.forEach((arr, index) => {
if(!isEqualArr(arr, outputArr[index])) outputArr.push(tempArr); // outputs correctly
});
if (i == 0) {
outputArr.push(tempArr);
tempArr = [];
}
}
}
}
}
return outputArr;
};
const isEqualArr = (a, b) => {
for (let i = 0; i < a.length; i++) {
if (a[i] != b[i]) {
return false;
}
}
return true;
};
console.log(threeSum([-1,0,1,2,-1,-4]));

Multiple array intersection in javascript

How to write in javascript(w/wth JQuery) to find values that intersect between arrays?
It should be like
var a = [1,2,3]
var b = [2,4,5]
var c = [2,3,6]
and the intersect function should returns array with value {2}. If possible it could applicable for any number of arrays.
Thanks
There are many ways to achieve this.
Since you are using jQuery I will suggest use grep function to filter the value that are present in all three array.
var a = [1, 2, 3]
var b = [2, 4, 5]
var c = [2, 3, 6]
var result = $.grep(a, function(value, index) {
return b.indexOf(value) > -1 && c.indexOf(value) > -1;
})
console.log(result)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Explanation: Loop over any array and filter out the values that are present in other array.
Update (for multimidensional array):
Concept - flatten the multidimensional array that is transform [[1,2],3,4] to [1,2,3,4] and then use the same logic used for single dimensional array.
Example:
var a = [
[1, 4], 2, 3
]
var b = [2, 4, 5]
var c = [2, 3, 6, [4, 7]]
//flatten the array's
//[1,4,2,3]
var aFlattened = $.map(a, function(n) {
return n;
})
//[2,4,5]
var bFlattened = $.map(b, function(n) {
return n;
})
//[2,3,6,4,7]
var cFlattened = $.map(c, function(n) {
return n;
})
var result = $.grep(aFlattened, function(value) {
return (bFlattened.indexOf(value) > -1 && cFlattened.indexOf(value) > -1);
});
console.log(result);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
// First this is how you declare an array
var a = [1,2,3];
var b = [2,4,5];
var c = [2,3,6];
// Second, this function should handle undetermined number of parameters (so arguments should be used)
function intersect(){
var args = arguments;
// if no array is passed then return empty array
if(args.length == 0) return [];
// for optimisation lets find the smallest array
var imin = 0;
for(var i = 1; i < args.length; i++)
if(args[i].length < args[imin].length) imin = i;
var smallest = Array.prototype.splice.call(args, imin, 1)[0];
return smallest.reduce(function(a, e){
for(var i = 0; i < args.length; i++)
if(args[i].indexOf(e) == -1) return a;
a.push(e);
return a;
}, []);
}
console.log(intersect(a, b, c));
First of all '{}' means Object in JavaScript.
Here is my suggestion.(this is another way of doing it)
// declarations
var a = [1,2,3];
var b = [2,4,5];
var c = [2,3,6];
// filter property of array
a.filter(function(val) {
if (b.indexOf(val) > -1 && c.indexOf(val) > -1)
return val;
});
what it does is it checks for each element in array 'a' and checks if that value is present in array 'b' and array 'c'. If it is true it returns the value. Simple!!!. The above code should work for String as well but it wouldn't work for IE < 9, so be careful.
// Intersecting 2 ordered lists of length n and m is O(n+m)
// This can be sped up by skipping elements
// The stepsize is determined by the ratio of lengths of the lists
// The skipped elements need to be checked after skipping some elements:
// In the case of step size 2 : Check the previous element
// In case step size>2 : Binary search the previously skipped range
// This results in the best case complexity of O(n+n), if n<m
// or the more propable complexity of O(n+n+n*log2(m/n)), if n<m
function binarySearch(array, value, start = 0, end = array.length) {
var j = start,
length = end;
while (j < length) {
var i = (length + j - 1) >> 1; // move the pointer to
if (value > array[i])
j = i + 1;
else if (value < array[i])
length = i;
else
return i;
}
return -1;
}
function intersect2OrderedSets(a, b) {
var j = 0;
var k = 0;
var ratio = ~~(b.length / a.length) - 1 || 1;
var result = [];
var index;
switch (ratio) {
case 1:
while (j < a.length) {
if (a[j] === b[k]) {
result.push(a[j]);
j++;
k++;
} else if (a[j] < b[k]) {
while (a[j] < b[k]) j++;
} else {
while (b[k] < a[j]) k++;
if (k >= b.length) break;
}
}
break;
case 2:
while (j < a.length) {
if (a[j] === b[k]) {
result.push(a[j]);
j++;
k++;
} else if (a[j] < b[k]) {
while (a[j] < b[k]) j++;
} else {
while (b[k] < a[j]) k += 2;
if (k - 1 >= b.length) break;
if (a[j] <= b[k - 1]) k--;
}
}
break;
default:
while (j < a.length) {
if (a[j] === b[k]) {
result.push(a[j]);
j++;
k++;
} else if (a[j] < b[k]) {
while (a[j] < b[k]) j++;
} else {
while (b[k] < a[j]) k += ratio;
index = binarySearch(b, a[j], k - ratio + 1, k + 1 < b.length ? k + 1 : b.length - 1);
if (index > -1) {
result.push(a[j]);
j++;
k = index + 1;
} else {
j++;
k = k - ratio + 1;
}
if (k >= b.length) break;
}
}
}
return result;
}
function intersectOrderedSets() {
var shortest = 0;
for (var i = 1; i < arguments.length; i++)
if (arguments[i].length < arguments[shortest].length) shortest = i;
var result = arguments[shortest];
for (var i = 0, a, b, j, k, ratio, index; i < arguments.length; i++) {
if (result.length === 0) return result;
if (i === shortest) continue;
a = result;
b = arguments[i];
result = intersect2OrderedSets(a, b);
}
return result;
}
How to use:
intersectOrderedSets(a,b,c);

Counting duplicates

the function below should count the number of letters in string (text) that occur more than once, i do not get why it does not work properly.
function duplicateCount(text){
text.toUpperCase();
var counter = "";
for (var i = 0; i < text.length; i++) {
for (b = 0; b < text.length; b++){
if(text[b] === text[i] && b !== i && counter.indexOf(text[b] === -1)) {
counter += text[b];
}
}
}
return counter.length;
replace if(text[b] === text[i] && b !== i && counter.indexOf(text[b] === -1)) with if(text[b] === text[i] && b !== i && counter.indexOf(text[b]) === -1)
function duplicateCount(text){
counterString = ""
for (var i = 0; i < text.length; i++) {
if(text.indexOf(text[i], i+1) != -1) {
counterString = counterString + text[i]
}
}
alert(counterString.length);
}
an easy solution
duplicates are a,b,c,d,f = 5
function duplicateCount(text){
text = text.toUpperCase('');
var text_arr = [];
var total = 0;
for (var i = 0; i < text.length; i++) {
var char = text.substring(i, 1);
if(text_arr.indexOf(text[i]) == -1) {
text_arr.push(text[i]);
} else {
total++;
}
}
return total;
}
console.log('Total duplicate characters are: '+duplicateCount('aabbccddeff'));
Hope it helps.
In addition to the answer by Krishna Kishore Andhavarapu,
the second line of your code should be replaced by
var text = text.toUpperCase();

finding prime numbers in an array from 1-200

A math problem describes a list of numbers from 1-200, you must skip the number 1, and then for each number that follows, remove all multiples of that number from the list. Do this until you have reached the end of the list.
Here's what I have so far.
var x = []; // creating an array called x with zero numbers
for ( var i = 1; i <= 200; i++ ){
x.push(i);
};
// x now should have an array that contains the intergers from 1-200.
//looping through the array.
for ( var i = 0; i <= x.length; i++ ){ //going from 1-200
if (x[i] == 1){
continue; // skipping 1
} else {
for ( var n = i+1; n <= i; n++){ // take the number 1 index bigger than x[i]
if ( n % i == 0){ //find if the modulus of x[n] and x[i] is zeor, meaning it is divisible by x[i]
x.shift(); //remove that number
console.log(x[n]);
} else {
continue;
}
}
}
};
Instead of adding number 1 to 200 and then removing non prime numbers, try only putting prime numbers into that list. Since this is a school problem (I'm guessing) I don't want to give you the answer, but if you have more questions I can answer.
Also your nested loop will never run, go over that logic again.
Another version (a minute too late, as always ;-), one with comments
// lil' helper
function nextSet(a,n){
while(a[n] == 0) n++;
return n;
}
function setPrimes(a,n){
var k, j, r;
n = n + 1;
k = n;
while(k--)a[k] = 1;
a[0] = 0; // number 0
a[1] = 0; // number 1
// get rid of all even numbers
for(k = 4; k < n; k += 2) {
a[k] = 0;
}
// we don't need to check all of the numbers
// because sqrt(x)^2 = x
r = Math.floor(Math.sqrt(n));
k = 0;
while(k < n){
k = nextSet(a,k+1);
// a test if we had them all
if(k > r){
break;
}
// unmark all composites
for(j = k * k; j < n; j += 2*k){
a[j] = 0;
}
}
return a;
}
function getPrimes(n){
// we know the size of the input
var primearray = new Array(n);
// we don't know the size of the output
// prime-counting is still an unsolved problem
var output = [];
setPrimes(primearray, n);
for(var i = 0; i < n; i++){
if(primearray[i] == 1){
output.push(i);
}
}
return output;
}
getPrimes(200);
You can go through a full implementation of that algorithm at another primesieve.
Here is, I believe, a working example of what you want:
function isPrime(num){
if(num < 2){
return false;
}
for(var i=2,l=Math.sqrt(num); i<=l; i++){
if(num % i === 0){
return false;
}
}
return true;
}
function range(f, t){
for(var i=f,r=[]; i<=t; i++){
r.push(i);
}
return r;
}
function primeRange(from, to){
var a = range(from, to), r = [];
for(var i=0,l=a.length; i<l; i++){
var v = a[i];
if(isPrime(v)){
r.push(v);
}
}
return r;
}
var prmRng = primeRange(1, 200);
console.log(prmRng);
I solved it this way:
let numbers = new Array();
for (let i = 1; i <= 200; i++) {
numbers.push(i);
}
let primeNumbers = (num) => {
let prime = new Array();
for(let i = 0; i < num.length; i++) {
let count = 0;
for (let p = 2; p <= num[i]; p++) {
if(num[i] % p === 0 && num[i] !== 2) {
count++;
} else {
if(num[i] === 2 || count === 0 && num[i]-1 === p) {
prime[i] = num[i];
}
}
}
}
return prime.filter(Boolean);
}
console.log(primeNumbers(numbers));

How to compare two arrays in JavaScript?

If I have two arrays as parameters how can I find the starting index where the second parameter occurs as a sub-array in the array given as the first parameter.
E.g.: [5,9,3,6,8], [3,6] should return 2.
Is there a function in JavaScript for this, or does it just loop through both of them and compare?
findArrayInArray = function(a, b) {
var ai = a.length
, bi = b.length;
for(var i=0; i<ai; i++) {
if (a[i] === b[0]) {
if(bi === 1) return i;
for(var x=1; x<bi; x++) {
if(a[i+x] === b[x]) {
if(x === bi-1) return i;
} else {
break;
}
}
}
}
}
var arr1 = [5,9,3,6,8];
var arr2 = [3,6];
console.log(findArrayInArray(arr1,arr2)); // 2
http://jsfiddle.net/ymC8y/3/
In direct answer to your question, there is no built in function in JS to look in an array for a sub-array.
You will have to do some sort of brute force looping search like this or use some external library function that already has array comparison logic. Here's what a brute force solution in plain JS looks like:
function findSubArrayIndex(master, sub) {
for (var m = 0; m < master.length - sub.length + 1; m++) {
for (var s = 0; s < sub.length; s++) {
if (master[m + s] !== sub[s]) {
break;
} else if (s === sub.length - 1) {
return m;
}
}
}
return -1;
}
Working demo: http://jsfiddle.net/jfriend00/mt8WG/
FYI, here's a somewhat performance optimized version of this function:
function findSubArrayIndex(master, sub) {
var subLen = sub.length, subFirst, m, mlen;
if (subLen > 1) {
subFirst = sub[0];
for (m = 0, mlen = master.length - subLen + 1; m < mlen; m++) {
if (master[m] === subFirst) {
for (var s = 1; s < subLen; s++) {
if (master[m + s] !== sub[s]) {
break;
} else if (s === subLen - 1) {
return m;
}
}
}
}
} else if (subLen === 1) {
subFirst = sub[0];
for (m = 0, mlen = master.length; m < mlen; m++) {
if (master[m] === subFirst) {
return m;
}
}
}
return -1;
}
Working demo: http://jsfiddle.net/jfriend00/CGPtX/
function index (a, b) {
var as = new String(a),
bs = new String(b),
matchIndex = as.indexOf(bs);
if (matchIndex === -1) {
return -1;
} else if (matchIndex === 0) {
return 0;
}
return as.substring(0, matchIndex + 1).match(/,/g).length;
}
console.log(index([5,9,3,6,8], [3, 6]));
Try this - You loop through both arrays and compare each element:
var arr1 = [5,9,3,6,8];
var arr2 = [3,6];
findArrayInArray = function(arr1, arr2) {
for(var i=0; i<arr1.length; i++) {
for(var j=0; j<arr2.length; j++){
if(arr1[i] === arr2[j]){
return i;
}
}
}
return false;
}
findArrayInArray(arr1, arr2);

Categories

Resources