How do I compare two arrays for different message outcomes? - javascript

I am trying to compare two arrays( containing 3 integers) and return a hint message array that conform to the logic
-Push “Almost” when 1 digit and position match in array
-push “not quite” when 1 digit matches but different position
-push “incorrect “ when no digits match
push “correct” When exact match
Example of arrays :
Array1 = [2,7,6]
ReferenceArray= [2,9,7]
Hint= [“Almost”, “Not Quite”];
Code I have so far:
function check( array1, referenceArray ) {
let hint=[];
for(i=0;i<referenceArray.length;i++){
for (j=0;j<Array1.length;j++){
//value and position match
if ((referenceArray[i] && reference.indexOf[i]) === (Array1[j] && Array1.indexOf[j])) {
return hint.push('almost');
}
//value matches but not position
else if(( referenceArray[i] ===Array1[j]) && !(referenceArray.indexOf[i]===Array1.indexOf[j] )){
return hint.push('not quite');
}
}// end of Array1 iteration
} // end of reference interation
// if all values and position match
if(referenceArray===Array1){
return hint.push("correct");
}
//if no values match
else if (referenceArray!==Array1){
return hintArray.push("incorrect");
}

I would use some built in Array methods to help achieve this: every(), map() and findIndex().
I generally avoid using .push() because it mutates the array. Immutable code is nice to read 😉
const check = (array, referenceArray) => {
if (array.every((val, index) => val === referenceArray[index] )) {
return ['Correct']
}
const allHints = array.map((val, index) => {
const refArrayIndex = referenceArray.findIndex(refVal => val === refVal);
if (refArrayIndex === index) {
return 'Almost'
}
if (refArrayIndex !== -1) {
return 'Not Quite'
}
return undefined
});
const hints = allHints.filter((hint) => hint !== undefined);
if (hints.length > 0) {
return hints;
}
return ['Incorrect']
};
const hints = check([2,7,6],[2,9,7]);
console.log('hints', hints)

I did this code, tell me if it works or not 😁
const array1 = [2,7,6]
const ReferenceArray = [2,9,7]
function compareArrays(arr){
let perfect = true
for(let i = 0; i < ReferenceArray.length; i++){
if(ReferenceArray[i] != arr[i]) {
perfect = false
break
}
}
if(perfect) return 'correct'
let hint = []
for(let i = 0; i < ReferenceArray.length; i++){
if(arr[i] == ReferenceArray[i]) hint.push('Almost')
else if(ReferenceArray.includes(arr[i])) hint.push('Not Quite')
}
if(hint.length > 0) return hint
return 'incorrect'
}
console.log(compareArrays(array1))

Related

Return true if the string in the first element of the array contains all of the letters of the string in the second element

I tried to do this by resetting loop going trough firstword every time its letter matches with secondword letter.
function mutation(arr) {
var compare = [];
var firstword = arr[0].toLowerCase();
var secondword = arr[1].toLowerCase();
var j = 0;
for (let i = 0; i < firstword.length; i++) {
if (firstword[i] === secondword[j]) {
compare.push(secondword[i]);
i = -1;
j++;
}
}
let result = compare.join("")
if (result.length === secondword.length) {
return true;
} else {
return false;
}
}
console.log(mutation(["Noel", "Ole"]));
It works in some cases but in others, like above example, it doesn't. What seems to be the problem?
You need to compare.push(secondword[j]) instead of compare.push(secondword[i])
function mutation(arr) {
var compare = [];
var firstword = arr[0].toLowerCase();
var secondword = arr[1].toLowerCase();
var j = 0;
for (let i = 0; i < firstword.length; i++) {
if (firstword[i] === secondword[j]) {
compare.push(secondword[j]); // Correction here
i = -1;
j++;
}
}
let result = compare.join("");
if (result.length === secondword.length) {
return true;
} else {
return false;
}
}
console.log(mutation(["Noel", "Ole"]));
Also, you can consider using Array.prototype.every.
const mutation = ([first, sec]) => {
const lowerCaseFirst = first.toLowerCase();
const lowerCaseSec = sec.toLowerCase();
return Array.from(lowerCaseSec).every((ch) => lowerCaseFirst.includes(ch));
};
console.log(mutation(["Noel", "Ole"]));
If the strings are small then String.prototype.includes works fine but if they are large then you should consider using a Set.
const mutation = ([first, sec]) => {
const firstSet = new Set(first.toLowerCase());
const lowerCaseSec = sec.toLowerCase();
return Array.from(lowerCaseSec).every((ch) => firstSet.has(ch));
};
console.log(mutation(["Noel", "Ole"]));
Simple ES6 Function, we check with .every() if every characters of secondword is includes inside firstword. It return true if it does.
function mutation(arr) {
const firstword = arr[0].toLowerCase();
const secondword = arr[1].toLowerCase();
return secondword.split('').every(char => firstword.includes(char));
}
console.log(mutation(["Noel", "Ole"]));
The use of Set in SSM's answer works if you don't need to account for duplicate characters in the second string. If you do, here's an implementation that uses a Map of character counts. The map key is the character from string 1 and the value is the number of occurrences. For instance, if you want ["Noel", "Ole"] to return true, but ["Noel", "Olle"] to return false (string 1 does not contain 2 "l" characters). String 2 is then iterated through and character counts decremented if they exist. As soon as a character is not present or the count falls below 1 in the map, the function returns false.
function mutation(arr: string[]): boolean {
return s1ContainsAllCharsInS2(arr[0].toLowerCase(), arr[1].toLowerCase());
}
function s1ContainsAllCharsInS2(s1: string, s2: string): boolean {
if (s2.length > s1.length) {
return false;
}
let charCountMap: Map<string, number> = new Map<string, number>();
Array.from(s1).forEach(c => {
let currentCharCount: number = charCountMap.get(c);
charCountMap.set(c, 1 + (currentCharCount ? currentCharCount : 0));
});
return !Array.from(s2).some(c => {
let currentCharCount: number = charCountMap.get(c);
if (!currentCharCount || currentCharCount < 1){
return true;
}
charCountMap.set(c, currentCharCount - 1);
});
}
A different approach.
Mapping the characters and comparing against that map.
function mutation(arr) {
const chars = {};
for (let char of arr[0].toLowerCase()) {
chars[char] = true;
}
for (let char of arr[1].toLowerCase()) {
if (!chars[char]) {
return false;
}
}
return true;
}
console.log(mutation(["Noel", "Ole"]));
console.log(mutation(["Noel", "Oleeeeeeeeeeeee"]));
If the count also matters (your code doesn't take it into account) you can count the number of occurrences of each character and comparing these counts.
function mutation(arr) {
const chars = {};
for (let char of arr[0].toLowerCase()) {
chars[char] = (chars[char] || 0) + 1;
}
for (let char of arr[1].toLowerCase()) {
// check if chars[char] contains a (not empty == positive) count
// then decrement it for future checks
if (!chars[char]--) {
return false;
}
}
return true;
}
console.log(mutation(["Noel", "Ole"]));
console.log(mutation(["Noel", "Oleeeeeeeeeeeee"]));

Find Missing Character in a Character Array (javascript)

I am trying to write a function that takes in an array of individual characters (eg.['a','b','d']) and returns the first character that is missing (eg. 'c'). I am not sure why my current function doesn't work as described.
const alph = "abcdefghijklmnopqrstuvwxyz";
const findMissingLetter = (arr) => {
arr.forEach((l, i, a) => {
const ltrIdx = alph.indexOf(l); //a's index in the alph is 0
const arrNxtLtr = a[i+1]; //the next ltr after a is c
if(arrNxtLtr !== alph[ltrIdx + 1]) return alph[ltrIdx + 1] //return the letter that is missing from the arr
})
return -1 //return -1 if there is no missing char
}
console.log(findMissingLetter(['a','c']))
ps. I've seen similar approaches to solve this general problem, I am just simply wondering what I've done wrong with my function so I can learn.
Thank you!
If you simply want to find the first mismatch between two strings, then just compare them character by character until you find a mismatch or reach the end of the input string:
const alph = "abcdefghijklmnopqrstuvwxyz";
const findMissingLetter = (arr) => {
for(let i=0; i<arr.length; i++) {
if(arr[i] !== alph[i]) {
return alph[i]; // found the first mismatch
}
}
return -1 // return -1 if there is no missing char
}
console.log(findMissingLetter([]),"-1?");
console.log(findMissingLetter(['a']),"-1?");
console.log(findMissingLetter(['b']),"a?");
console.log(findMissingLetter(['a','b']),"-1?");
console.log(findMissingLetter(['a','c']),"b?");
And avoid forEach() if you want to return from inside a loop as it was commented already.
And if the input string does not have to start at the beginning of the "big" string, locate it's first character and do the comparison from there:
const alph = "abcdefghijklmnopqrstuvwxyz";
const findMissingLetter = (arr) => {
if(arr.length===0)
return -1;
let start = alph.indexOf(arr[0]);
for(let i=0; i<arr.length; i++) {
if(arr[i] !== alph[start+i]) {
return alph[start+i]; // found the first mismatch
}
}
return -1 // return -1 if there is no missing char
}
console.log(findMissingLetter([]),"-1?");
console.log(findMissingLetter(['a']),"-1?");
console.log(findMissingLetter(['b']),"-1?");
console.log(findMissingLetter(['a','b']),"-1?");
console.log(findMissingLetter(['a','c']),"b?");
console.log(findMissingLetter(['b','c','e','f']),"d?");
The reason is that forEach ignores return or any shortcircuit statement. You must instead of trying return the value from the foreach, just save it into another variable and return that variable after the forEach is done.
const alph = "abcdefghijklmnopqrstuvwxyz";
const findMissingLetter = (arr) => {
let missingLetter
arr.forEach((letter, index) => {
if(letter !== alph[index]) missingLetter ??= alph[index]
else missingLetter = -1
})
return missingLetter
}
console.log(findMissingLetter(['a','c']))

How to find the longest common prefix in an array of strings?

I'm trying to solve this using the .every method but it's not returning true and therefore it's not adding onto my string and I'm not sure why.
var longestCommonPrefix = function(arr) {
if (arr.length === 0) {
return undefined;
}
let result = '';
for (let i = 0; i < arr.length; i++) {
if (arr.every(x => arr[i].charAt(i) === x)) {
result += arr[i].charAt(i);
}
}
return result
}
console.log(longestCommonPrefix(["flower", "flow", "flight"])); //fl
You need to iterate over one string, not over the whole array: check if the first character of the string is present everywhere, then the second character, etc:
var longestCommonPrefix = function(arr) {
if (arr.length === 0) {
return undefined;
}
let result = '';
for (let i = 0; i < arr[0].length; i++) {
if (arr.every(x => x.charAt(i) === arr[0][i])) {
result += arr[i].charAt(i);
} else break;
}
return result;
}
console.log(longestCommonPrefix(["flower", "flow", "flight"])); //fl
Your use of Array.every is along the right lines. You want to check that every string in the array has the same character at position i. I think you got confused when you named the parameter x, when it is in fact a string :)
var longestCommonPrefix = function(words) {
if (words.length === 0) {
return "";
}
const letters = [];
const lengthOfShortestWord = Math.min(...words.map(word => word.length));
for (let i = 0; i < lengthOfShortestWord; i++) {
const char = words[0][i];
if (words.every(word => word[i] === char)) {
letters.push(char);
} else {
break;
}
}
return letters.join("");
}
console.log(longestCommonPrefix(["flower", "flow", "flight"])); //fl
Unless I am mistaken the longest prefix is never going to be greater than the smallest string in the array.
In this case "fl" is both the smallest string and the longest common prefix:
["flower", "fl", "flight"]
So start with finding the smallest string in arr:
let [sm] = [...arr].sort((a, b) => a.length - b.length);
Then check that all strings in arr start with sm:
arr.every(str => str.startsWith(sm));
If that isn't the case then shorten sm by one character:
sm = sm.slice(0, -1);
And keep going until you eventually find the longest prefix or sm becomes an empty string:
const prefix = arr => {
let [sm] = [...arr].sort((a, b) => a.length - b.length);
while (sm && !arr.every(str => str.startsWith(sm))) sm = sm.slice(0, -1);
return sm;
};

Comparing equality of elements in two arrays

I have an assignment where I am supposed to check two arrays (unsorted) with integers, to see if
They have the same length
The first element contains integers and the second has the same values squared, in any order
For example:
test([5,4,1], [1,16,25]) // would return true ..
What I've done so far is first sort the two input arrays, and then compare the length. Once we confirm the length is the same we iterate through each value to make sure they're equal. Keep in mind I haven't gotten to comparing the values to their squared counterpart yet, because my loop is not giving me expected results. Here is the code:
function test(arr1, arr2){
// sort arrays
const arr1Sort = arr1.sort(),
arr2Sort = arr2.sort();
// compare length and then compare values
if(arr1Sort.length === arr2Sort.length) {
for(let i = 0; i < arr1Sort.length; i++) {
if(arr1Sort[i] === arr2Sort[i]) {
return true;
} else {
return false;
}
}
}
}
console.log(test([1,2,3], [1,5,4])); returns true but the array values are different?!
Inside the for, no matter whether the if or else is fulfilled, the function will immediately return true or false on the first iteration - it'll never get past index 0. To start with, return true only after the loop has concluded, and return false if arr1Sort[i] ** 2 !== arr2Sort[i] (to check if the first squared equals the second).
Also, when sorting, make sure to use a callback function to compare each item's difference, because otherwise, .sort will sort lexiographically (eg, [1, 11, 2]):
function comp(arr1, arr2){
// sort arrays
const sortCb = (a, b) => a - b;
const arr1Sort = arr1.sort(sortCb),
arr2Sort = arr2.sort(sortCb);
// compare length and then compare values
if(arr1Sort.length !== arr2Sort.length) {
return false;
}
for(let i = 0; i < arr1Sort.length; i++) {
if(arr1Sort[i] ** 2 !== arr2Sort[i]) {
return false;
}
}
return true;
}
console.log(comp([1,2,3], [1,5,4]));
console.log(comp([5,4,1], [1,16,25]));
You can decrease the computational complexity to O(N) instead of O(N log N) by turning arr2 into an object indexed by the squared number beforehand:
function comp(arr1, arr2){
if (arr1.length !== arr2.length) {
return false;
}
const arr2Obj = arr2.reduce((a, num) => {
a[num] = (a[num] || 0) + 1;
return a;
}, {});
for (let i = 0; i < arr1.length; i++) {
const sq = arr1[i] ** 2;
if (!arr2Obj[sq]) {
return false;
}
arr2Obj[sq]--;
}
return true;
}
console.log(comp([1,2,3], [1,5,4]));
console.log(comp([5,4,1], [1,16,25]));
(if duplicates weren't permitted, this would be a lot easier with a Set instead, but they are, unfortunately)
This should work, no mater the data to compare:
function similar(needle, haystack, exact){
if(needle === haystack){
return true;
}
if(needle instanceof Date && haystack instanceof Date){
return needle.getTime() === haystack.getTime();
}
if(!needle || !haystack || (typeof needle !== 'object' && typeof haystack !== 'object')){
return needle === haystack;
}
if(needle === null || needle === undefined || haystack === null || haystack === undefined || needle.prototype !== haystack.prototype){
return false;
}
var keys = Object.keys(needle);
if(exact && keys.length !== Object.keys(haystack).length){
return false;
}
return keys.every(function(k){
return similar(needle[k], haystack[k]);
});
}
console.log(similar(['a', {cool:'stuff', yes:1}, 7], ['a', {cool:'stuff', yes:1}, 7], true));
// not exact
console.log(similar(['a', {cool:'stuff', yes:1}, 7], ['a', {cool:'stuff', stuff:'more', yes:1}, 7, 'more stuff only at the end for numeric array']));

Test If The Array Index Equals The Array Value

The code is to return the lowest index in an array when the value in the array is the same as the index. If there are no matches i should return -1. For example:
indexEqualsValue([-8,0,2,5])
output: 2 //array[2] == 2
indexEqualsValue([-1,0,3,6])
output: -1 //no matches
The code works when there are no matches or if the length of the array is zero, but not at other times. I think the problem is the first condition in my if statement. I don't necessarily want an answer, more tips on what I should check/rewrite.
Thanks!
function indexEqualsValue(a) {
return a.reduce((acc, currV, currI) => {
if (currI === currV) {
return currV;
}
return -1;
}, 0);
}
You could just find the index with Array#findIndex.
const indexEqualsValue = array => array.findIndex((v, i) => v === i);
console.log(indexEqualsValue([-8, 0, 2, 5])); // 2
console.log(indexEqualsValue([-1, 0, 3, 6])); // -1
some exits when it matches, so you can use it to quickly find what you need:
const indexEqualsValue = array => {
let match;
const didMatch = array.some((v, i) => {
match = i;
return v === i;
})
return didMatch ? match : -1;
}
console.log(indexEqualsValue([-8,0,2,5]))
console.log(indexEqualsValue([-8,0,2,5,0]))
console.log(indexEqualsValue([-1,0,3,6]))
nina-scholz's answer is better, the only advantage of using some over findIndex is that some is supported in ie whereas it seems findIndex is not.
for(i = 0,c=0;i < arr.length; i++ ) {
if(arr[i] == i) {
c = 1;
break;
}
}
if( c == 0 ) {
print(c);
} else {
print (i);
}

Categories

Resources