简体   繁体   中英

JAVA - Compare two arrays and create a new array with only the unique values from the first

I have to solve an exercise with the following criteria:

Compare two arrays:

int[] a1 = {1, 3, 7, 8, 2, 7, 9, 11};
int[] a2 = {3, 8, 7, 5, 13, 5, 12};

Create a new array int[] with only unique values from the first array. Result should look like this: int[] result = {1,2,9,11};

NOTE: I am not allowed to use ArrayList or Arrays class to solve this task.

I'm working with the following code, but the logic for the population loop is incorrect because it throws an out of bounds exception.

public static int[] removeDups(int[] a1, int[] a2) {
    //count the number of duplicate values found in the first array
    int dups = 0;
    for (int i = 0; i < a1.length; i++) {

        for (int j = 0; j < a2.length; j++) {
            if (a1[i] == a2[j]) {
                dups++;
            }
        }
    }
    //to find the size of the new array subtract the counter from the length of the first array
    int size = a1.length - dups;
    //create the size of the new array
    int[] result = new int[size];

    //populate the new array with the unique values
    for (int i = 0; i < a1.length; i++) {
        int count = 0;
        for (int j = 0; j < a2.length; j++) {
            if (a1[i] != a2[j]) {
                count++;
                if (count < 2) {
                    result[i] = a1[i];
                }
            }
        }
    }

    return result;
}

I would also love how to solve this with potentially one loop (learning purposes).

I offer following soulution.

  1. Iterate over first array, and find out min and max it's value.
  2. Create temporary array with length max-min+1 (you could use max + 1 as a length, but it could follow overhead when you have values eg starting from 100k).
  3. Iterate over first array and mark existed values in temorary array.
  4. Iterate over second array and unmark existed values in temporary array.
  5. Place all marked values from temporary array into result array.

Code:

public static int[] getUnique(int[] one, int[] two) {
    int min = Integer.MAX_VALUE;
    int max = Integer.MIN_VALUE;

    for (int i = 0; i < one.length; i++) {
        min = one[i] < min ? one[i] : min;
        max = one[i] > max ? one[i] : max;
    }

    int totalUnique = 0;
    boolean[] tmp = new boolean[max - min + 1];

    for (int i = 0; i < one.length; i++) {
        int offs = one[i] - min;
        totalUnique += tmp[offs] ? 0 : 1;
        tmp[offs] = true;
    }

    for (int i = 0; i < two.length; i++) {
        int offs = two[i] - min;

        if (offs < 0 || offs >= tmp.length)
            continue;
        if (tmp[offs])
            totalUnique--;
        tmp[offs] = false;
    }

    int[] res = new int[totalUnique];

    for (int i = 0, j = 0; i < tmp.length; i++)
        if (tmp[i])
            res[j++] = i + min;

    return res;
}

For learning purposes, we won't be adding new tools.

Let's follow the same train of thought you had before and just correct the second part:

// populate the new array with the unique values
for (int i = 0; i < a1.length; i++) {
    int count = 0;
    for (int j = 0; j < a2.length; j++) {
        if (a1[i] != a2[j]) {
            count++;
            if (count < 2) {
                result[i] = a1[i];
            }
        }
    }
}

To this:

//populate the new array with the unique values
int position = 0;
for (int i = 0; i < a1.length; i++) {
    boolean unique = true;

    for (int j = 0; j < a2.length; j++) {
        if (a1[i] == a2[j]) {
            unique = false;
            break;
        }
    }

    if (unique == true) {
        result[position] = a1[i];
        position++;
    }
}

I am assuming the "count" that you implemented was in attempt to prevent false-positive added to your result array (which would go over). When a human determines whether or not an array contains dups, he doesn't do "count", he simply compares the first number with the second array by going down the list and then if he sees a dup (a1[i] == a2[j]), he would say "oh it's not unique" (unique = false) and then stop going through the loop (break). Then he will add the number to the second array (result[i] = a1[i]).

So to combine the two loops as much as possible:

// Create a temp Array to keep the data for the loop
int[] temp = new int[a1.length];

int position = 0;
for (int i = 0; i < a1.length; i++) {
    boolean unique = true;

    for (int j = 0; j < a2.length; j++) {
        if (a1[i] == a2[j]) {
            unique = false;
            break;
        }
    }

    if (unique == true) {
        temp[position] = a1[i];
        position++;
    }
}

// This part merely copies the temp array of the previous size into the proper sized smaller array
int[] result = new int[position];

for (int k = 0; k < result.length; k++) {
    result[k] = temp[k];
}

Making your code work

Your code works fine if you correct the second loop. Look at the modifications I did:

//populate the new array with the unique values
int counter = 0;
for (int i = 0; i < a1.length; i++) {
    for (int j = 0; j < a2.length; j++) {
        if (a1[i] == a2[j]) {
              result[counter] = a1[i];
              counter++;
        }
    }
}




The way I would do it

Now, here is how I would create a method like this without the need to check for the duplicates more than once. Look below:

public static int[] removeDups(int[] a1, int[] a2) {
    int[] result = null;
    int size = 0;

    OUTERMOST: for(int e1: a1) {
      for(int e2: a2) {
        if(e1 == e2)
          continue OUTERMOST;
      }

      int[] temp = new int[++size];
      if(result != null) {
        for(int i = 0; i < result.length; i++) {
          temp[i] = result[i];
        }
      }

      temp[temp.length - 1] = e1;
      result = temp;
    }

    return result;
}

Instead of creating the result array with a fixed size, it creates a new array with the appropriate size everytime a new duplicate is found. Note that it returns null if a1 is equal a2 .

You can make another method to see if an element is contained in a list :

public static boolean contains(int element, int array[]) {
    for (int iterator : array) {
        if (element == iterator) {
            return true;
        }
    }
    return false;
}

Your main method will iterate each element and check if it is contained in the second:

int[] uniqueElements = new int[a1.length];
int index = 0;
for (int it : a1) {
   if (!contains(it, a2)) {
       uniqueElements[index] = it;
       index++;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM