2

I have two arrays:

const array1 = ["A", "S", "S", "G"]; // multiple occurrences of 'S'.
const array2 = ["S", "F", "J", "A"]; // single occurrence of 'S'.

I want to match the array2 with array1 for each of the instances. So I made a function:

const matchedArray = (array1, array2) => {
    let finalArray = [];
    array1.forEach((char, idx) => array2.includes(char) ? finalArray[idx] = `✅${char}` : finalArray[idx] = char);
    return finalArray;
}

But as you can understand that .includes() matches with all the instances of that character. So a single instance of "S" on the array2 matches with the two Ss of the array1. So the function is returning:

["✅A", "✅S", "✅S", "G"]

How can I achieve the finalArray be like:

["✅A", "✅S", "S", "G"]
Mayeenul Islam
  • 4,532
  • 5
  • 49
  • 102
  • I'm not sure what you're asking - is it that you want that once a char in `array2` was used in a match it can't be used again? – Guss Jul 03 '23 at 20:51

5 Answers5

1

What I might do is create a dictionary of counts of the values in array2.

{ "A": 1, "S": 1, "F": 1, "J": 1 }

Then use a loop to process each element of array1. If the count is greater than 0, replace and decrement. Otherwise, do nothing.

const array1 = [ "A", "S", "S", "G" ];
const array2 = [ "S", "F", "J", "A" ];

const counts = { };
array2.forEach(
   _ => { counts[ _ ] = ( counts[ _ ] || 0 ) + 1; }
);

const finalArray = array1.map(
   ( _, i ) => counts[ _ ] && counts[ _ ]-- ? `✅${_}` : _
);

console.log( finalArray );

Very efficient, even for long lists (O(N+M)).

ikegami
  • 367,544
  • 15
  • 269
  • 518
  • Initially, I's stuck with the _ (underscores) in the code. I thought that could be _something_ special here. But then I found it's just a placeholder :). This works well and easy to understand in human eyes. – Mayeenul Islam Aug 03 '23 at 18:55
  • 1
    @Mayeenul Islam, It's the default var name for loos in Perl. (`for ( LIST )` is short for `for $_ ( LIST )`). I use it in other languages when I don't know over what I'm interacting. A generic variable name, similar to how `i` is used as a generic array index variable. Feel free to use a more meaningful name. – ikegami Aug 03 '23 at 19:33
  • In fact, you don't even have a choice with `map` in Perl. It always uses `$_`. `my %counts; ++$counts{ $_ } for @array2; my @finalArray = map { $counts[ $_ ] && $counts[ $_ ]-- ? "✅$_" : $_ } @array1;` – ikegami Aug 03 '23 at 19:41
1

Just count and decrement the count.

const
    array1 = ["A", "S", "S", "G"],
    array2 = ["S", "F", "J", "A"],
    hash = array2.reduce((h, s) => {
        h[s] = (h[s] || 0) + 1;
        return h;
    }, {}),
    result = array1.map(s => hash[s] && hash[s]-- ? '✅' + s : s);

console.log(result);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
1

You could check if your array already contains the resulting product, and then not add that.

const array1 = ["A", "S", "S", "G"]; // multiple occurrences of 'S'.
const array2 = ["S", "F", "J", "A"]; // single occurrence of 'S'.

const matchedArray = (array1, array2) => {
    let finalArray = [];
    array1.forEach((char, idx) => array2.includes(char) && !finalArray.includes(`✅${char}`) ? finalArray[idx] = `✅${char}` : finalArray[idx] = char);
    return finalArray;
}

console.log(matchedArray(array1, array2));
Nils Kähler
  • 2,645
  • 1
  • 21
  • 26
  • This doesn't work for multiple occurrences of "S". Though the question was with a single occurrence, but eventually dealing with multiple occurrences is necessary in my case, I'm afraid. – Mayeenul Islam Aug 03 '23 at 18:44
0

You can just use a Set to store all the char's that have already been used. And use the .has to to check, finally add the used chars using .add.

eg.

const array1 = ["A", "S", "S", "G"]; // multiple occurrences of 'S'.
const array2 = ["S", "F", "J", "A"]; // single occurrence of 'S'.

const matchedArray = (array1, array2) => {
  let finalArray = [];
  const used = new Set();
  array1.forEach((char, idx) => {
    array2.includes(char) && !used.has(char) ? finalArray[idx] = `✅${char}` : finalArray[idx] = char;
    used.add(char);
  });
  return finalArray;
}

console.log(matchedArray(array1,array2));
Keith
  • 22,005
  • 2
  • 27
  • 44
0

Here is a single-step solution using Array#map and Array#includes methods:

const 
      array1 = ["A", "S", "S", "G"], // multiple occurrences of 'S'.
      array2 = ["S", "F", "J", "A"], // single occurrence of 'S'.
      
      matchedArray = array1.map(
          (char,i) => array2.includes(char) && !array1.slice(0,i).includes(char) ? `✅${char}` : char
      );

console.log( matchedArray );
PeterKA
  • 24,158
  • 5
  • 26
  • 48