2

I am attempting to check if a list of long's does not contain a certain value. It would seem as though that condition is never met, even though I know that one value does not exist in a certain linked list...

for(int i : organizationIDs){
    if(!ListOfOrgIds.contains(Long.valueOf(i))){
        addThese.add(new Long(i));
    }
}

I am essentially looking for value that doesn't exist in the orgID's array, if it doesn't exist, add it to the addThese linked list... Am I missing some nuance with Long's that I should know?

ListOfOrgIds as found in the debugger

14057
821
18021

OrganizationIDs as found in the debugger

821
14057
18021

Let me just put it this way, I am looking right at the debugger, and it is telling me that ListOfOrgIds.contains(i) is false... which is patently untrue...enter image description here

To be specific, look at the the values of ListOfOrgs...

enter image description here

821 is indeed in there. Why am I getting a false on the contains call?

Leandro Bardelli
  • 10,561
  • 15
  • 79
  • 116
SoftwareSavant
  • 9,467
  • 27
  • 121
  • 195
  • Can you show some more code.. As this part of code seems correct.. Unless there is no problem with `addThese.add()` or the `ListOfOrgIds` that we don't know how they look.. – Rohit Jain Sep 25 '12 at 17:27
  • BTW, why have you created a `List` of `Long` even though you are adding `integer` values to them?? – Rohit Jain Sep 25 '12 at 17:29
  • 1
    Should be fine (although you can use the same `Long` twice) - please show a short but *complete* program demonstrating the problem. – Jon Skeet Sep 25 '12 at 17:32
  • Can you please give us an example of the `listOfOrgIds` and `organizationIDs` lists? – Fritz Sep 25 '12 at 17:32
  • Well the consumer is passing in an Array of ints. It's part of the contract (I am writing a webservice) ListoFOrgIds is fine. There really is not much more to show... I just set up the list and get the values – SoftwareSavant Sep 25 '12 at 17:33
  • 1
    @DmainEvent -> `as you can see, 14057 is not in ListOfOrgIds `.. Doesn't seem.. We see this value in both list.. Still we are not getting an insight of what you are doing?? Can you post complete code?? – Rohit Jain Sep 25 '12 at 17:39
  • That is complete code... But that might be something worth looking into? Maybe I am accidentally setting up the same list – SoftwareSavant Sep 25 '12 at 18:11
  • You say 14057 is not in ListofOrgIds, although it clearly is, according to your debugger output? – Jin Kim Sep 25 '12 at 18:17

2 Answers2

2

The problem you are having is that java does not allow a primitive to be widened then boxed, only boxed then widened. This means an int cannot become a Long, but an int could become an Object (via Integer). The top answer to this question describes it fairly well. You don't get any compilation feedback in this case as the contains method does not use the type parameter of list, it accepts any object. This has caught me out many times in the past too.

Below is a SSCCE showing both the result you are getting, and a working example. Note all that is required is to explicitly cast the int to a long.

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class BoxingTest {

    public static void main(String[] args) throws Exception {

        List<Integer> intList = Arrays.asList(new Integer[]{14, 24, 69});
        List<Long> sourceLongList = Arrays.asList(new Long[]{14L, 17L});

        List<Long> resultsList;
        /* Test as in question code */
        resultsList = new ArrayList<Long>();
        for(int i : intList){
            if(!sourceLongList.contains(i)){
                resultsList.add(new Long(i));
            }
        }
        printList(resultsList);

        /* Can't box then widen, so cast */
        resultsList = new ArrayList<Long>();
        for(int i : intList){
            if(!sourceLongList.contains((long)i)){
                resultsList.add(new Long(i));
            }
        }
        printList(resultsList);

    }

    private static <T> void printList(List<T> values){
        StringBuilder contents = new StringBuilder();
        for(T value : values){
            contents.append(value);
            contents.append(" ");
        }
        System.out.println("List contains: " + contents);
    }

}
Community
  • 1
  • 1
David Hutchison
  • 2,343
  • 2
  • 19
  • 24
1

First point I'd like to make is that it seems like you'd be better off using Set since it doesn't allow duplicate elements. In other words, doing:

Set<Long> ids = new HashSet<Long>();
ids.add(Long.valueOf(1));
ids.add(Long.valueOf(1));
System.out.println(ids.size());

Will print 1, not 2 like it would for a List.

I'm not sure what exact operation you're looking for, but there are three possible ones that you want: union, intersection, and relative complement. For their formal definitions and Venn diagrams, see this Wikipedia section on the Set page.

Union

Result: all elements in A and B will be in C.

To perform this operation:

Set<Long> a = ... ;
Set<Long> b = ... ;
Set<Long> c = new HashSet<Long>(a);
c.addAll(b);

Intersection

Result: only elements in both A and B will be in C.

To perform this operation:

Set<Long> a = ... ;
Set<Long> b = ... ;
Set<Long> c = new HashSet<Long>(a);
c.retainAll(b);

Relative Complement

Result: C will contain all elements in A except the ones that were in B

To perform this operation:

Set<Long> a = ... ;
Set<Long> b = ... ;
Set<Long> c = new HashSet<Long>(a);
c.removeAll(b);

Additionally, to convert a List to a Set:

List<Long> idsAsList = ... ;
Set<Long> idsAsSet = new HashSet<Long>(idsAsList);

To convert an array to a Set, you have to do things differently depending on if you have a long[] or a Long[] (notice the caps). For long[], you have to copy manually:

long[] idsAsArray = ... ;
Set<Long> idsAsSet = new HashSet<Long>();
for (long l : idsAsArray) {
    idsAsSet.add(Long.valueOf(l));
}

If it's Long[], you can use Arrays.asList:

Long[] idsAsArray = ... ;
Set<Long> ids = new HashSet<Long>(Arrays.asList(idsAsArray));
Brian
  • 17,079
  • 6
  • 43
  • 66
  • not really to concerned with dupes. What on earth is a set anyway? Somekind of hashtable? I accidentally copied the same variable output. That will be reflected when I update my post. – SoftwareSavant Sep 25 '12 at 19:01
  • A set is another collection type that doesn't allow duplicates. Think of it like a list but without ordering (which is probably not relevent in your case) and without the possibility for duplicate elements (probably not desired in your case). In this case, it's also much faster because for any `List`, `removeAll` and `retainAll` are _O(n) = n^2_, but `HashSet` is _O(n) = n_. Behind the scenes, it's implemented using a sort of hash table, but it's not a hash table per se because it doesn't "map" like a hash table. – Brian Sep 25 '12 at 19:05
  • Also, were you the one that downvoted my answer? Downvotes should only be used when the solution is technically incorrect or doesn't answer the question. See the answers to [this question](http://meta.stackexchange.com/questions/2451/why-do-you-cast-downvotes-on-answers) for information on how seasoned SO members feel downvotes should (and should not) be used. – Brian Sep 25 '12 at 19:14
  • I did down vote because I feel as though your post did not answer my question. While all this set stuff is interesting, I am a little confused as to why my list won't say that something is not in it when it definitely is not... You didn't even show an equivalent example using sets. If you edit your post I will upgrade the answer. – SoftwareSavant Sep 25 '12 at 19:21
  • I'm not sure this answers the question either. The question uses the ‘List‘ API for starters, and even if it was using ‘Set‘ you've overwhelmed the op with too much information when simply the ‘removeAll‘ method would have been sufficient. – ramsinb Sep 25 '12 at 21:47