1

I have two variables with numbers and I need to figure out which to know what parts are the same. I would like to do this even with more than just two strings if possible.

I could use (var1.indexOf(?) > -1 && var2.indexOf(?) > -1), but I'd have to cover every possible number. (or letter, if I wanted to compare strings)

If it helps in my specific case, these numbers coming from the following type of variable as an example:

const originalVar1 = [1,3,2,0,6]
const var1 = originalVar1.sort().join('');
  const var1 = '01236';
  const var2 = '12345';
  let same = '';
  for (let i = 0; i < 10; i++) {
    same += (var1.indexOf(i) > -1 && var2.indexOf(i) > -1) ? `${i}` : '';
  }
  console.log(same); // Outputs: 123

My solution works but feels like there should be some built in function or method to do this already. Maybe my solution could be more elegant as it doesn't cover all characters.

Examples:

var1 = '01456'
var2 = '0246'
whatIsTheSame(var1, var2) // Expected output: 046

var1 = '12359'
var2 = '035679'
whatIsTheSame(var1, var2) // Expected output: 359

Another Solution

shash678 solution below works perfectly for getting 1 instance of every character that appears in every variable. The following solution gives you all instances of every character that appears in every variable.

    value = [ '39291', '3902', '3039903', '39039311873', '3737298' ]
    value.sort((a, b) => b.length - a.length);
    let matches = value[0];
    for (let i = 1; i < value.length; i++) {
        matches = (matches.match(new RegExp(`[${value[i]}]`, 'g')) || []).join('');
    }
    console.log(matches); // Outputs: 393933

This is based on these answers here:

https://stackoverflow.com/a/51179953/11866303 Sort array by length

https://stackoverflow.com/a/41708135/11866303 Regex solution

It's possible this could be more elegant but I'm not the best. Thanks everyone.

KarnEdge
  • 15
  • 3
  • Are two variables with numbers? or to strings with numbers? And are the numbers ordered as in the examples? – Charly.Org Aug 16 '19 at 22:16
  • 1) If you want to retain the leading zeros then you will have to use strings, e.g. `const var1 = "01236";`. 2) I notice that the digits in the examples are monotonically increasing - is that always the case or could there be a "12321"? – Andrew Morton Aug 16 '19 at 22:23
  • These numbers are from a joined sorted array of numbers from 0 to 6. I am making sure which numbers match between these sets of variables. – KarnEdge Aug 16 '19 at 22:27
  • So you need to figure out which individual characters in `var1` are also in `var2`? – Ry- Aug 16 '19 at 22:29
  • @Ry- yes that's correct – KarnEdge Aug 16 '19 at 22:33
  • @AndrewMorton That solution does in fact work for comparing 2 variables' characters. Thanks! Unfortunately, I now have to figure out how to make it work with more than 2 variables. – KarnEdge Aug 16 '19 at 22:40
  • @KarnEdge: Can you describe the whole, real problem you’re trying to solve? – Ry- Aug 16 '19 at 22:42
  • @KarnEdge It works for more than two: apply it to two, then use that result with the third variable, and so on. If you have a *lot* to intersect, you may want to investigate intersecting pairs and intersecting the results of the pairs. – Andrew Morton Aug 16 '19 at 22:47
  • Here's an efficient approach for any number of strings in an array: `var sets = ["01456", "0246"] .map(s => s.split("")) .map(a => new Set(a)); var chars = Array.from(sets.reduce((t, c) => Array.from(c).reduce((t2, c2) => t2.add(c2), t), new Set())); chars.sort(); chars.filter(c => sets.every(s => s.has(c)))` – StriplingWarrior Aug 16 '19 at 22:51
  • (And I should specify that by "efficient" I mean that its performance will not increase disproportionately as the number of inputs, or the length of inputs, increases. It may be slower than other approaches for specific, small inputs, especially if you have a known, limited set of possible values.) – StriplingWarrior Aug 16 '19 at 22:59
  • 1
    @StriplingWarrior: Why create `chars`? `let strings = ["01456", "0246"]; let sets = strings.map(s => new Set(s)); Array.from(strings[0]).filter(c => sets.every(s => s.has(c)));` – Ry- Aug 16 '19 at 23:48
  • @Ry-: I had no idea the set constructor would break down a string like that. Thanks for sharing! – StriplingWarrior Aug 19 '19 at 14:59

2 Answers2

2

Use the spread operator and reduce to handle your requirement of n number of arguments:

const whatIsTheSameHelper = (s1, s2) => {
  const s2Set = new Set(s2)
  return new Set([...s1].filter(x => s2Set.has(x)))
}

const whatIsTheSame = (...vars) => {
  return vars.reduce(whatIsTheSameHelper)
}

const var1 = '01236'
const var2 = '12345'
const var3 = '0246'
console.log(whatIsTheSame(var1, var2, var3))

Output:

Set { '2' }
Sash Sinha
  • 18,743
  • 3
  • 23
  • 40
  • 1
    This is the perfect solution for me and anyone who needs to know 1 instance of every character that appears in all variables. You can use the Regex solution from the duplicate question's answer to be able to get every instance (not just 1) of every character that appears in all variables by just wrapping the Regex in a for loop. – KarnEdge Aug 16 '19 at 23:35
  • This code has an error in execution: `s1.filter is not a function` – StriplingWarrior Aug 19 '19 at 15:08
  • 1
    It's also really inefficient, creating a duplicate set for every call to `s1.filter`. – StriplingWarrior Aug 19 '19 at 15:28
  • @StriplingWarrior I fixed the bug, any recommendations how to not create a duplicate set? – Sash Sinha Aug 19 '19 at 17:21
  • Yeah, just extract that `new Set(s2)` to a variable that gets initialized within the helper, but outside of the filter lambda. That will make the biggest difference, by an order of magnitude. – StriplingWarrior Aug 20 '19 at 15:05
  • @StriplingWarrior done. – Sash Sinha Aug 20 '19 at 16:38
0

The general ES6 solution to getting the intersection of two arrays in O(m + n) time is to put one in a Set and filter the other according to which values are in the set:

const intersection = (array1, array2) => {
    const set2 = new Set(array2);
    return array1.filter(x => set2.has(x));
};

// alternatively, (array1, array2) => array1.filter(Set.prototype.has, new Set(array2));

const originalVar1 = [1, 3, 2, 0, 6];
const originalVar2 = [2, 4, 3, 1, 5];
console.log(intersection(originalVar1.sort(), originalVar2.sort()));

This preserves the order of array1. If you only have the strings left at the time you need to do the intersection, the function is similar.

Ry-
  • 218,210
  • 55
  • 464
  • 476
  • Just out of curiosity, why are you sorting the input arrays? – StriplingWarrior Aug 19 '19 at 15:14
  • @StriplingWarrior: The question specified that the inputs were sorted. Sorting the output instead is more efficient, yes, if that’s what you’re getting at :) – Ry- Aug 19 '19 at 23:06