Reputation: 1949
I have the below code which checks to make sure at least one value in array 1 appears in array 2.
As long as it does, it will check if any initials (values of one character in length) exist in array2.
If there are, it will check if that initial matches the first letter of any value in array1.
var array1 = ['Bob', 'Freddy', 'Johnson'];
var array2 = ['Bob', 'Johnson', 'F'];
var isValid = '';
if (array1.some(v => array2.includes(v)) == true) { //At least one value in array 1 appear in array 2
if (anyInitials(array2) == 'yes') { // initials appear in array 2
if (findName(array2, array1) == true) { //check initials in array 2 vs array 1
isValid = 'yes';
} else { //let's check the inverse, just in case
isValid = 'no';
}
}
}
console.log('Do we match? = ' + isValid);
function findName(arr1, arr2) {
for (let initial of arr1) {
if (initial.length === 1) {
return arr2.findIndex(name => name[0] === initial) != -1
}
}
}
function anyInitials(a) {
var arrayLength = a.length;
var isInitials = 'no';
for (var i = 0; i < arrayLength; i++) {
if (a[i].length == 1) {
isInitials = 'yes';
}
}
return isInitials;
}
It all works fine but I have problems in more convoluted scenarios such as below:
var array1 = ['Bob','Freddy', 'Johnson', 'Frank'];
var array2 = ['Bob', 'Johnson', 'Frank', 'F'];
How can I ensure that the initial "F" in array2 is being tested against "Freddy" in array1 and not "Frank" (because Frank exists in both arrays, it should be ignored)?
Also,
var array1 = ['Bob','Freddy', 'Johnson', 'Frank', 'Frederic'];
var array2 = ['Bob', 'Johnson', 'F', 'F'];
In the above, the first "F" should test against "Freddy" and the second "F" should test against "Frank" because Freddy was already matched. However, we have a remainder in "Frederic", which does not have a corresponding match (there are no names left in array2) so isValid should say 'no';
A more complex situation:
var array1 = ['Bob','F', 'Freddy', 'Johnson', 'Frank'];
var array2 = ['Bob', 'J', 'F', 'Johnson', 'Freddy'];
"J" should not find a match because "Johnson" already has a pair. One "F" should automatically match with it's pair, while the second "F" should test against the remaining "Frank". This leaves "Frank" to test against "J", which should return "no".
It doesn't matter which name in array 1 the initial in array2 pairs with at this point. What matters is whether or not it can pair at all.
Either array can contain as many or as few values (to a minimum of 1 in each).
Thank you
Addendum: the proposed solution thus far would involve removing all matching names from both arrays, leaving only those values that differ in each. This still leaves me with the problem of matching an initial to a name (a modified findName function). These such pairs would then need to be removed from both arrays, leaving only the remainders in each array (if any). If there are remainders in array1, then isValid would say 'no".
Upvotes: 2
Views: 98
Reputation: 92367
Try
function check(array1, array2) {
let i1 = array1.map( x => array2.indexOf(x) );
let i2 = array2.map( x => array1.indexOf(x) );
let a1 = array1.filter( (x,i) => !i2.includes(i) );
let a2 = array2.filter( (x,i) => !i1.includes(i) );
let j2 = a2.map( x => a1.reduce( (a,y,j)=> x[0]==y[0] ? j : -1, -1 ) );
return j2.reduce((a,c)=> a||c>-1, false)
}
The i1
contains indexes (form array2) of array1 elements in array2 (or -1 if element from array1 not appear in array2). The a2
contains elements from array2 excluding elements from array1. Symmetric situation is for i2
and a1
. The array j2
element has value >-1
if corresponding a2
element first letter x[0]
appear as first letter in some element of a1
(y[0]
). We return true if j2
contains at least one non negative value.
function check(array1, array2) {
let i1 = array1.map( x => array2.indexOf(x) );
let i2 = array2.map( x => array1.indexOf(x) );
let a1 = array1.filter( (x,i) => !i2.includes(i) );
let a2 = array2.filter( (x,i) => !i1.includes(i) );
let j2 = a2.map( x => a1.reduce( (a,y,j)=> x[0]==y[0] ? j : -1, -1 ) );
return j2.reduce((a,c)=> a||c>-1, false)
}
// TEST
var array1 = ['Bob','Freddy', 'Johnson'];
var array2 = ['Bob', 'Johnson', 'F'];
console.log('test 1', check(array1, array2));
var array1 = ['Bob','Freddy', 'Johnson', 'Frank'];
var array2 = ['Bob', 'Johnson', 'Frank', 'F'];
console.log('test 2', check(array1, array2));
var array1 = ['Bob','Freddy', 'Johnson', 'Frank', 'Frederic'];
var array2 = ['Bob', 'Johnson', 'F', 'F'];
console.log('test 3', check(array1, array2));
var array1 = ['Bob','F', 'Freddy', 'Johnson', 'Frank'];
var array2 = ['Bob', 'J', 'F', 'Johnson', 'Freddy'];
console.log('test 4', check(array1, array2));
Upvotes: 0
Reputation: 207501
You can not really do it in one step, you are going to have to do it in two.
var names1 = ['Bob','Freddy', 'Johnson', 'Frank', 'Frederic'];
var names2 = ['Bob', 'Johnson', 'F', 'F', 'F'];
var names3 = ['Bob', 'Johnson', 'F', 'F', 'G'];
var names4 = ['Bob', 'Johnson', 'F', 'F'];
function test (array1, array2) {
// If lenghts differ, then it fails
if (array1.length !== array2.length) {
return false
}
// copy arrays so you do not alter orginals
var first = array1.slice()
var second = array2.slice()
// remove the exact matches
array1.forEach( function (name, index) {
var secondIndex = second.indexOf(name)
if (secondIndex > -1) {
first.splice(first.indexOf(name), 1)
second.splice(secondIndex, 1)
}
})
// if all matched, then we pass
if (!first.length) {
return true;
}
// now check to see if we have a abv match,
// every item in the array needs a match to pass
return first.every(function (text) {
var index = -1
// if we have a full name, than match first
if (text.length > 1) {
var index = second.indexOf(text[0])
} else {
// we have an initial so need to first letter in full name
var index = second.findIndex( function (secondText) {
return text === secondText[0]
})
}
// if we do not have a match then we have a failure
if (index === -1) {
return false
} else {
// when we have a match, remove it from the second so it can not be used again
second.splice(index, 1)
return true
}
})
}
console.log(1, test(names1, names1))
console.log(2, test(names1, names2))
console.log(3, test(names2, names1))
console.log(4, test(names1, names3))
console.log(5, test(names3, names1))
console.log(6, test(names1, names4))
Upvotes: 1