7

So, basically i have two Arrays:

int[] listA = {2, -5, -121, 102, -35, -2, 0, -125, 802, -10};
int[] listB = {6, 99, -1, 12, 1, -2};

and I want to fill in a new array (listD) all elements of listA that are missing from listB.

The output should be like this:

Output: 2, -5, -121, 102, -35, 0, -125, 802, -10

My code is the following:

int arraySize = 0; //Variable to determine size of the new array;
int difElements = 0; //Variable to count every different element;

for(int i = 0; i < listA.length; i++){
    for(int j = 0; j < listB.length; j++){
        if(listA[i] != listB[j]){
            difElements++;
        }
        if(difElements == listB.length){
        arraySize++;
    }

    }
     difElements = 0;
}
System.out.println("Size of the array with different elements : " + arraySize);

int[] listD = new int [arraySize]; //Declaring array with specified size;

I then use the following for loop to run trough both arrays and check if there are repeated elements:

for (int i = 0; i < listA.length; i++) {
    for (int j = 0; j < listB.length; j++) {
        if (listA[i] != listB[j]) {
            listD[i] = listA[i];
        } else {
            listD[i] = listA[i + 1];
        }
    }
}

I know what's wrong with the loop, using Debugger it's quite easy to see where it goes wrong, but at this point i'm just running in circles and coding the same mistakes... After the loop finds the repeated element i can't find a way to normalize the condition (listD[i] = listA[i]) since it has skipped a postion. Maybe I need another loop just to iterate trough listD but I've never nested three loops before...

Bare in mind this is really basic java programming, these are just exercises from my class to get the basics of java programming. I have no knowledge of any POO, classes, methods etc etc and can't apply them of course.

Kirill Simonov
  • 8,257
  • 3
  • 18
  • 42
ramireeez
  • 152
  • 1
  • 6

7 Answers7

2

I suggest you to use one temporary array (say listC) to store the positions of the elements that we need to copy.

Iterating through both arrays for the first time, you calculate the size of the new array and set flags if the elements are unique.

Then you iterate through the listC and copy the unique elements from listA

int[] listA = {2, -5, -121, 102, -35, -2, 0, -125, 802, -10, 7, 555};
int[] listB = {6, 99, -1, 12, 1, -2, 7, 555};

// array of flags indicating which elements of listA to copy
int[] listC = new int[listA.length];

// counter of unique elements from listA
int counter = 0;

for (int i = 0; i < listA.length; i++) {
    boolean contains = false;
    //simplified form of for loop if you don't use an index
    for (int b: listB) {
        if (listA[i] == b) {
            contains = true;
            break;
        }
    }
    if (!contains) {
        counter++;
        //setting listC[i] to 1 if listA[i] is not present in listB
        listC[i] = 1;
    }
}

// declaring array with specified size 
int[] listD = new int[counter];

counter = 0;

// iterating through the array of flags to copy unique elements
for (int i = 0; i < listC.length; i++) {
    if (listC[i] == 1) {
        listD[counter++] = listA[i];
    }
}

System.out.println(Arrays.toString(listD));
Kirill Simonov
  • 8,257
  • 3
  • 18
  • 42
  • wow, so simple! Thank you so much mate :) Just a quick question, when using an boolean like this, why did you declare and put it under the for loop? couldn't you declare it before the for loop as false, and only use the condition "contains = true" aftwerwards? – ramireeez Jan 31 '18 at 00:20
  • @Rui I was glad to help! I put `boolean contains = false;` inside the `for (int i = 0; i < listA.length; i++)` loop because I need to check this condition for each element of `listA`. If I declared it outside the loop, I would have to assign it to `false` at each iteration anyway. However, [the scope of local variables should always be the smallest possible](https://stackoverflow.com/a/8803806/8629960). There is also a [more detailed answer](https://stackoverflow.com/a/8878071/8629960) – Kirill Simonov Jan 31 '18 at 01:48
  • Ok, understood it completely! Thanks a bunch mate :) – ramireeez Jan 31 '18 at 23:13
1

If you use java 8 you can use this.

List<Integer> aList = Arrays.stream(listA).boxed().collect(Collectors.toList());
List<Integer> bList = Arrays.stream(listB).boxed().collect(Collectors.toList());

aList.removeIf(o -> bList.contains(o));
Chamly Idunil
  • 1,848
  • 1
  • 18
  • 33
1

You can use a marker something of boolean type to identify

  1. Element that is in listA and not in listB.
  2. Duplicate not found for adding to new list.

Now the code starts with three arrays one listA, listB, listC. listC can only have size same as listA, because that's the maximum (worst case that no elements of listA match with listB). Plus I'm adding my markers

int[] listA = {2, -5, -121, 102, -35, -2, 0, -125, 802, -10, 0, 2};
int[] listB = {6, 99, -1, 12, 1, -2};
int[] listC = new int[listA.length];
boolean elementFound = true;
boolean duplicateFound = false;
int thirdArrayIndex = 0;
int zeroCount = 0;

We will come to markers elementFound and duplicateFound later. First we will do the basic nested iteration

for(int i=0; i< listA.length; i++) {
    boolean elementFound = true;
    for(int j=0; j< listB.length; j++) {

Asking to iterate listB with each element of listA. Now inside the loop for listB we keep a code for checking similarity of elements and setting the unique element mark.

if(listA[i] == listB[j]) {
    elementFound = false;
    break;
}

If element in listA matches with listB keep elementFound as false and break the inner loop because no need to search again. That takes the execution to outer loop where we will check whether elementFound. If it is true then only proceed to add the element.

The adding part will be like this

if(elementFound) {
    boolean duplicateFound = false;
    for(int k=0; k< listC.length; k++) {
        if((listA[i] == listC[k]) || (listA[i] == 0 && ++zeroCount > 1)) {
            duplicateFound = true;
            break;
        }
     }
     if(!duplicateFound) {
         listC[thirdArrayIndex++] = listA[i];
     }
}

Before the next for loop starts we will keep duplicateFound as false. Inside for loop we will check two conditions

  1. Whether element not in listA is already present in listC.
  2. The initial listC will be having all elements initialized with 0. So even if listA is having element as 0 and which is not present in listB, it won't be added to listC because 0 is already present according to condition-1.

That's why the condition is like if((listA[i] == listC[k]) || (listA[i] == 0 && ++zeroCount > 1)). Initially value of zeroCount is 0, so when a 0 is found in listA not in listB

listA[i] == 0 --> true &&
++zeroCount(value = 1) >= 2 --> false

So the first 0 in listA will be added. After the for loop with k is over or either breaked we will check not condition of duplicateFound, ie no duplicate found in listC, if that's true the go and add element of listA to listC

listC[thirdArrayIndex++] = listA[i]; // listC[0] = listA[i]; first time

Only after the execution of this line the value of thirdArrayIndex will be incremented refer How do the post increment (i++) and pre increment (++i) operators work in Java?.

Now when for loop with i is finished all the elements in listA not matching with listB will be added to listC, but if matching elements are found not all listA elements will be added to listC, so rest of the listC elements will be having value 0. That's why we will use a fourth array listD to copy only the elements from listC that were added from listA.

That's where thirdArrayIndex have its significance, by now thirdArrayIndex means the total number of elements added from listA to listC. So the last part of the code will be like

int[] listD = new int[thirdArrayIndex];
for(int i=0; i<listD.length; i++) {
    listD[i] = listC[i];
}

Finally print all the arrays

System.out.println(java.util.Arrays.toString(listA));
System.out.println(java.util.Arrays.toString(listB));
System.out.println(java.util.Arrays.toString(listC));
System.out.println(java.util.Arrays.toString(listD));

So final program will be like

int[] listA = {2, -5, -121, 102, -35, -2, 0, -125, 802, -10, 0, 2};
int[] listB = {6, 99, -1, 12, 1, -2};
int[] listC = new int[listA.length];                
int thirdArrayIndex = 0;
int zeroCount = 0;

for(int i=0; i< listA.length; i++) {
    boolean elementFound = true;
    for(int j=0; j< listB.length; j++) {
        if(listA[i] == listB[j]) {
            elementFound = false;
            break;
        }
    }           
    if(elementFound) {
        boolean duplicateFound = false;
        for(int k=0; k< listC.length; k++) {
            if((listA[i] == listC[k]) || (listA[i] == 0 && ++zeroCount > 1)) {
                duplicateFound = true;
                break;
            }
        }
        if(!duplicateFound) {
            listC[thirdArrayIndex++] = listA[i];
        }
    }
}
int[] listD = new int[thirdArrayIndex];
for(int i=0; i<listD.length; i++) {
    listD[i] = listC[i];
}
System.out.println(java.util.Arrays.toString(listA));
System.out.println(java.util.Arrays.toString(listB));
System.out.println(java.util.Arrays.toString(listC));
System.out.println(java.util.Arrays.toString(listD));
Arun Sudhakaran
  • 2,167
  • 4
  • 27
  • 52
0

You can add all elements of listB to a HashSet hashSet, then iterate through each element of listA and check if the element is in the hashSet using hashSet.contains(). If it returns false, then add to listD.

Raj
  • 1
  • 2
0

Just use List.

int[] listA = {2, -5, -121, 102, -35, -2, 0, -125, 802, -10};
int[] listB = {6, 99, -1, 12, 1, -2};

List<Integer> b = Arrays.stream(listB).boxed().collect(Collectors.toList());

List<Integer> d = new ArrayList<>();
for (int i: listA) {
    if (!b.contains(i)) {
        d.add(i);
    }
}
Thien Nguyen
  • 359
  • 1
  • 3
  • 14
  • Thanks mate, but i was looking for an answer without using any methods for the java API, but loops and conditions. is there a way? – ramireeez Jan 24 '18 at 02:51
0

If you want to do without using list, it's better to maintain a boolean array to mark a elements of listA true if it is in listB and k gives us no of similar elements between listA and listB. So the resultant array will be of size listA.length-k and you can simply add elements after that

int[] listA = {2, -5, -121, 102, -35, -2, 0, -125, 802, -10};
int[] listB = {6, 99, -1, 12, 1, -2};

int k=0;
boolean isInB[] = new boolean[listA.length];

for(int i=0;i<listA.length;i++){
    for(int j=0;j<listB.length;j++){
        if(listA[i] == listB[j]){
            isInB[i] = true;
            k++;
            break;
        }
    }
}

int[] listResult = new int[listA.length-k];
int r=0;

for(int i=0;i<listA.length;i++){
    if(isInB[i] == false){
        listResult[r] = listA[i];
        r++;
    }
}
  • 1
    That's the same idea as in my answer. But you seem to do some redundant iterations in your nested loop - if `listA[i] == listB[j]` you do not need to iterate through `listB` anymore. – Kirill Simonov Jan 24 '18 at 05:03
  • @KirillSimonov yup we can break out from the loop –  Jan 24 '18 at 05:22
0

Let me give my 5 cents.

I agree, that this problem could be solved with plain old Java or using streams. But I think, that you do not think about element duplication, that could be important. E.g. listA = 2,2,2 and listB = 2,2. So I think, that one 2 is missing, so it should be in output.

I give you my approach, it works with this situation and with unique elements as well. I do not use streams to be simple and clear, but you could minimize it using streams:

private static int[] missing(int[] listA, int[] listB) {
    Map<Integer, Integer> map = new LinkedHashMap<>();

    for (int val : listB)
        map.put(val, map.getOrDefault(val, 0) + 1);

    int total = 0;

    for (int val : listA) {
        int count = map.getOrDefault(val, 0) - 1;
        map.put(val, count);

        if (count < 0)
            total++;
    }

    int i = 0;
    int[] listD = new int[total];

    for (Map.Entry<Integer, Integer> entry : map.entrySet())
        if (entry.getValue() < 0)
            for (int j = entry.getValue(); j < 0; j++)
                listD[i++] = entry.getKey();

    return listD;
}
Oleg Cherednik
  • 17,377
  • 4
  • 21
  • 35