Home > Software design >  How to count duplicates in two unsorted arrays
How to count duplicates in two unsorted arrays

Time:10-13

I need to compare the guess and code arrays and count the number of correct digits in the guess.

It works until there are duplicate numbers in the code array. I know it's something to do with the second for loop and subtracting from the correctDigits.

public static int digits(int[] code, int[] guess) {
    int digits = 0;
    
    for (int i = 0; i < code.length; i  ) {
        for (int j = 0; j < guess.length; j  ) {
            if (guess[j] == code[i]) {
                digits  ;
                break;
            }
        }
    }
    
    for (int i = 0; i < code.length; i  ) {
        for (int j = i   1; j < code.length; j  ) {
            if (code[i] == code[j] && code[i] != guess[j] && code[j] != guess[i]) {
                digits--;
            }
        }
    }
    
    return digits;
}

CodePudding user response:

Since you mentioned "only using loops and basic knowledge" I assume concepts like maps are not included here and "basic knowledge" means "arrays".

If all you need to know is the number of digits try to convert your input to a 10-element array of counts, i.e. each digit would be the input.

Example:

int[] codeDigits = new int[10];
for (int i = 0; i < code.length; i  ) {
   codeDigits[code[i]]  ;
}

This would turn [5,9,9,9] into [0,0,0,0,0,1,0,0,0,3], i.e. 5: 1x, 9: 3x

Now do this for the guess as well, e.g. [0,0,9,9] becomes [2,0,0,0,0,0,0,0,0,2].

Now all you have to do is count the number of digits:

int counter = 0;
for( int i = 0; i < codeDigits.length; i   ) {
  if( codeDigits[i] >= guessDigits[i] ) {
    counter  = guessDigits[i]; //guessed the exact number or less -> use the guess
  } else {
     counter  = codeDigits[i]; //guessed more -> use the code
  }
}

If you are able to use a Math function then the loop body could be replaced by counter = Math.min(codeDigits[i], guessDigits[i]);.

One more illustration (with longer codes to illustrate better):

 code: [5,0,9,9,1,7,1]   ->   [1,2,0,0,0,1,0,1,0,2]
guess: [9,9,0,9,7,4,2]   ->   [1,0,1,0,1,0,0,1,0,3]
-----------------------------------------
minimum of each digit:         1,0,0,0,0,0,0,1,0,2

If you sum those minimums you get 4 correct digits: 1x 0, 1x 7, 2x 9

CodePudding user response:

there are several solutions. one of them is indexing duplicated values of code array, then check them at first loop (and remove the 2nd loop):

int correctDigits = 0;
int[] duplicateIndexes = new int[code.length];
for (int i=0; i < code.length; i  ) {
    if( duplicateIndexes[i] == 1) continue;
    for (int j=0; j < code.length; j  ) {
        if( core[i] == core[j]) {
             duplicateIndexes[j] == 1;
             continue;
        }
    }
 }

for (int i = 0; i < code.length; i  ) {
    if (duplicatedIndexes[i] == 1) continue;
    for (int j = 0; j < guess.length; j  ) {
        if (guess[j] == code[i]) {
            correctDigits  ;
            break;
        }
    }
}

CodePudding user response:

You can generate two Maps from these arrays, which associating a Value with its number of occurrences.

Then iterate over the entries of the Map obtained from the code array and compare its values with the corresponding values from the Map created based on the guess array. That would allow determining the number of correct/incorrect guesses.

CodePudding user response:

I hope this will work.
Code

     public static int getCorrectDigits(int[] code, int[] guess) {
    if (code.length != guess.length) {
         throw new IllegalArgumentException("Different lengths");
    }
    
    int correctDigits = 0;
    
    for (int i = 0; i < code.length; i  ) {  
            if (guess[i] == code[i]) {
                correctDigits  ;
        }
    }

    return correctDigits;
}

Output

Code - 5 9 9 9
Guess - 0 9 9 9
Passes - 3

Code - 5 9 9 9
Guess - 9 9 0 0
Passes - 1

Code - 5 9 9 9
Guess - 0 0 9 9
Passes - 2

Code - 5 9 9 9
Guess - 9 0 0 0
Passes - 0

CodePudding user response:

You need to change the for loop to iterate over the guess instead of iterate over the code array:

public static int getCorrectDigits(int[] code, int[] guess) {
    if (code.length != guess.length) {
        throw new IllegalArgumentException("Different lengths");
    }

    int correctDigits = 0;

    for (int i = 0; i < guess.length; i  ) {
        for (int j = 0; j < code.length; j  ) {
            if (guess[i] == code[j]) {
                correctDigits  ;
                break;
            }
        }
    }
    return correctDigits;



    @Test
void ex1() {
    assertEquals(3, ArrayComp.getCorrectDigits(new int[] {5,9, 9, 9}, new int[] {0,9,9,9}));
}    @Test
void ex2() {
    assertEquals(2, ArrayComp.getCorrectDigits(new int[] {5,9, 9, 9}, new int[] {9,9,0,0}));
}    @Test
void ex3() {
    assertEquals(2, ArrayComp.getCorrectDigits(new int[] {5,9, 9, 9}, new int[] {0,0,9,9}));
}    @Test
void ex4() {
    assertEquals(1, ArrayComp.getCorrectDigits(new int[]{5, 9, 9, 9}, new int[]{9, 0, 0, 0}));
}

CodePudding user response:

I thought I'd join in on the fun - maintain a boolean array of code digits used, requires only one nested loop and reverse the looping order:

public static int getCorrectDigits(int[] code, int[] guess) {
    if (code.length != guess.length) {
        throw new IllegalArgumentException("Different lengths");
    }
    
    int correctDigits = 0;
    boolean[] used = new boolean[code.length];
    
    for (int i = 0; i < guess.length; i  ) {
        for (int j = 0; j < code.length; j  ) {
            if (guess[i] == code[j] && !used[j]) {
                correctDigits  ;
                used[j] = true;
                break;
            }
        }
    }
    
    return correctDigits;
} 
  • Related