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.

1
  • I think, you have used wrong word instead "missing" should be "except" Commented Jan 24, 2018 at 2:55

7 Answers 7

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));
Sign up to request clarification or add additional context in comments.

3 Comments

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?
@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. There is also a more detailed answer
Ok, understood it completely! Thanks a bunch mate :)
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));

Comments

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));

Comments

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.

Comments

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);
    }
}

1 Comment

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?
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++;
    }
}

2 Comments

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.
@KirillSimonov yup we can break out from the loop
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;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.