Compare contents of two ArrayLists efficiently - java

Any idea why contains not working here, these statement always evaluating false firstSchema.contains(firstSchema.get(0))
List<String> firstSchema = new ArrayList<String>();
firstSchema.add(0,"test");
firstSchema.add(1,"testy");
if(!(firstSchema.contains(firstSchema))){
System.out.println("hey arraylist content matched");
}
I need to get true if any one or more or all elements from one arraylist matched with other arraylist elements

The simplest way to check if a list contains any elements from another list is to call contains() on one of the lists, passing each element as an argument in turn. Something like:
public <E> boolean slowListContains(List<E> a, List<E> b) {
for (E element : a) {
if (b.contains(element)) {
return true;
}
}
return false;
}
This is slow, however, because contains() is a linear operation (O(n)), and since we're calling it in a loop the slowListContains() function takes quadratic time (O(n^2)) which is poor. We can do better.
A Set (or more precisely a hash-based set such as HashSet) has an efficient contains() method which runs in less-than-linear time (constant time in the case of HashSet). Converting one or the other list into a Set will make the loop in slowListContains() much faster. Something like:
public <E> boolean fasterListContains(List<E> a, List<E> b) {
Set<E> aSet = new HashSet<>();
aSet.addAll(a);
for (E element : b) {
if (aSet.contains(b)) {
return true;
}
}
return false;
}
This isn't perfect, but it's certainly much faster than the naive solution. A slight improvement would be to always convert the smaller list into the Set, rather than the first one. You could also take arbitrary Iterable parameters rather than List parameters, then check if either of them are already a Set and if so skip the set-construction step.

Your if(!(firstSchema.contains(firstSchema))) loop is wrong. You are trying to find a match in list with itself. You can not check if a list contains itself.
From java doc below is how contains works
Returns <tt>true</tt> if this list contains the specified element.
More formally, returns <tt>true</tt> if and only if this list contains
at least one element <tt>e</tt> such that
<tt>(o==null ? e==null : o.equals(e))</tt>.

You are checking it incorrectly. See firstSchema.contains(firstSchema) is wrong arrayList.contains(arrayList) won't work.
Secondly (firstSchema.contains("test")) returns true as array list does contains test and ! negating the result will not pass if statement because !true = false.
if(firstSchema.contains("test")) {
System.out.println("Match found !");
}
if(!firstSchema.contains("test")) {
System.out.println("Match not found !");
}

If want to check if one list has matching elements , you can do something like this.
List<String> firstSchema = new ArrayList<String>();
firstSchema.add(0,"test");
firstSchema.add(1,"testy");
List<String> testList = new ArrayList<String>(firstSchema);
testList.removeAll(firstSchema);
if(testList.size()<firstSchema.size()){
System.out.println("some elements match");
}
You can also use retainAll similarly

The simplest way is to use Java 8 streams.
if(firstList.stream().anyMatch(secondList::contains))
System.out.println("Content matched");
For improved efficiency (if you're working with enough data for it to actually matter) and if possible (unique values), the secondList can be turned into a HashSet.

Related

how to check if all elements of java collection match some condition?

I have an ArrayList<Integer>. I want to check if all elements of the list are greater then or less then certain condition. I can do it by iterating on each element. But I want to know if there is any method in Collection class to get the answer like we can do to find maximum or minimum with Collections.max() and Collections.min() respectively.
If you have java 8, use stream's allMatch function (reference):
ArrayList<Integer> col = ...;
col.stream().allMatch(i -> i>0); //for example all integers bigger than zero
You can use Google guavas Iterables.all
Iterables.all(collection, new Predicate() {
boolean apply(T element) {
.... //check your condition
}
}
You cannot check values without iterating on all elements of the list.
for(Integer value : myArrayList){
if(value > MY_MIN_VALUE){
// do my job
}
}
I hope this will help

Check if values in one arraylist is present in another

I need to check if any of the values in one arraylist is present in another arraylist:
import java.util.ArrayList;
public class SampleCode {
ArrayList<Integer> in = new ArrayList<>();
ArrayList<Integer> is = new ArrayList<>();
public static void main(String[] args) {
new SampleCode().work();
}
public void work(){
in.add(3);in.add(4);in.add(5);
is.add(1);is.add(2);is.add(3);
if(is.containsAll(in)){
System.out.println("It does not contain");
}
}
}
It prints "It does not contain". I need to know if there is a way to compare these two arraylists and if any of the values are present in the other arraylist, it should return false. I know iterating can help. Is there any simple way to do this?
I think you can use
Collections.disjoint
which says
Returns true if the two specified collections have no elements in common.
so it will return false if there are any elements in common.
Another possible solution:
public static boolean containsNone(List<?> list, List<?> of) {
List<?> temp = new ArrayList<Object>(list);
temp.retainAll(of);
return temp.isEmpty();
}
For example:
List<String> ref = Arrays.asList("w1", "w2", "w3");
List<String> ok = Arrays.asList("w4", "w5");
List<String> ko = Arrays.asList("w1", "w5");
System.out.println(containsNone(ok, ref));
System.out.println(containsNone(ko, ref));
Prints:
true
false
Try this one
public void work(){
in.add(3);in.add(4);in.add(5);;
is.add(1);is.add(2);is.add(3);;
ArrayList<Integer> matched = new ArrayList<Integer>(in);
matched.retainAll(is);
if(matched.size()>0){
System.out.println(matched);
}else{
System.out.println("It does not contain");
}
}
Collection.indexOfSubList(List<?> source, List<?> target)
Returns the starting position of the first occurrence of the specified
target list within the specified source list, or -1 if there is no
such occurrence.
More formally, returns the lowest index i such that source.subList(i, i+target.size()).equals(target), or -1 if there is no such index. (Returns -1 if target.size() > source.size().)
This implementation uses the "brute force" technique of scanning over the source list, looking for a match with the target at each location in turn.
Collections.disjoint(Collection<?> c1, Collection<?> c2)
Returns true if the two specified collections have no elements in
common.
Care must be exercised if this method is used on collections that do not comply with the general contract for Collection. Implementations may elect to iterate over either collection and test for containment in the other collection (or to perform any equivalent computation). If either collection uses a nonstandard equality test (as does a SortedSet whose ordering is not compatible with equals, or the key set of an IdentityHashMap), both collections must use the same nonstandard equality test, or the result of this method is undefined.
Care must also be exercised when using collections that have restrictions on the elements that they may contain. Collection implementations are allowed to throw exceptions for any operation involving elements they deem ineligible. For absolute safety the specified collections should contain only elements which are eligible elements for both collections.
Note that it is permissible to pass the same collection in both parameters, in which case the method will return true if and only if the collection is empty.
Throws:
NullPointerException - if one collection contains a null element and null is not an eligible element for the other collection. (optional) NullPointerException - if one collection contains a null element and null is not an eligible element for the other collection. (optional) ClassCastException - if one collection contains an element that is of a type which is ineligible for the other collection. (optional)
Collections.disjoint(list1, list2);
is your answer
see Collections documentation
public boolean isListNotOverlapping(List<Integer> yourList1, List<Integer> yourList2) {
for(Integer i : yourList1) {
if (yourList2.contains(i)) {
return false;
}
}
return true;
}

Check if arraylist contains only nulls

I think there has to be a better way of doing this..
I have a call to a function that returns an ArrayList.
If that ArrayList only returns 10 null items (the default), is there a way of checking this without iterating through all 10 items to see if they are null?
As of Java 8, you can use Streams like this:
boolean nullsOnly = list.stream().noneMatch(Objects::nonNull);
Which is equal to:
boolean nullsOnly = list.stream().allMatch(x -> x == null)
And here you can see the more general way of testing that any list matches a given Predicate:
list.stream().allMatch(x -> /* Some testing function. */)
Generally, no; there is no other way to tell that an arbitrary ArrayList contains ten instances of null than to loop over it and make sure each element is null. You can forgo this, of course, if the size() of the list isn't equal to ten.
List<Object> arrayList = new ArrayList<Object>();
arrayList.isEmpty();
// first call returns true
arrayList.add(null);
// second call returns false
Object obj = new Object();
arrayList.add(obj);
arrayList.isEmpty();
// third call returns false
Is that what you wanted?
Multiple addition of nulls increments the size by one, but there isn't a concrete "easy way" of finding the number of null objects unless you loop the array list.
Are you trying to check if the ArrayList is empty? (i.e. myArrayList.isEmpty()) or are you trying to check if the ArrayList contains only null references? If you're trying to check if all entries are null then you will need to check each entry...
boolean isListOfNulls(List myList){
for(Object o: myList)
if(!(o == null))
return false;
return true;
}
try with the stream API.
boolean haveOnlyNulls = arraylist.stream().noneMatch(object -> object != null);
The best way to check is by using boolean allMatch(Predicate<? super T> predicate);
This
Returns whether all elements of this stream match the provided predicate. May not evaluate the predicate on all elements if not necessary for determining the result. If the stream is empty then true is returned and the predicate is not evaluated.
boolean hasAllNulls = list.stream().allMatch(Objects::isNull)
Change the default to an empty ArrayList and use isEmpty(). The present default is senseless.

Java: How to loop through three List<String>

I have three List<String> variables: classFiles, usernames, and fileDirectories. I have a String (a list of strings but I will be comparing every string in the list with the loop below) that consists of one item from each of the lists. I want to loop through all three lists and check if one value from all three of the lists are in the String
What would be the best way to go about this?
for(String classFile:classFiles) {
//if contains classfile statement
for(String username:usernames) {
//if contains username statement
for(String fileDirectory:fileDirectories) {
//if contains filedirectory statement
}
}
}
or
for(String classFile:classFiles) {
for(String username:usernames) {
for(String fileDirectory:fileDirectories) {
//if statement
}
}
}
or
for(String classFile:classFiles) {
//make list of files that contain classFile
}
for(String username:usernames) {
//remove items from list that do not contain username
}
for(String fileDirectory:fileDirectories){
//remove items from list that do not contain fileDirectory
}
Or is there a better way to do this?
EDIT: Example
classFiles - a1, a2, a3
usernames - noc1, noc2, noc3
fileDirectories - C:/projects/a1/noc1/example.java, C:/projects/a1/ad3/example.java
and the string to check
String - C:/bin/a1/noc1/example.class
what i want to do is if both the fileDirectory and String contain a classFile and username, then add it to a list
so in this example C:/bin/a1/noc1/example.class will be added to the list but C:/bin/a4/fd1/example.class wont be or C:/bin/a3/noc3/example.class would not be added
When you perform remove operations for-each loop is not best choice. You should use Iterator and remove on iterator to avoid concurrent modification exception.
Instead
for(String fileDirectory:fileDirectories){
//remove items from list that do not contain fileDirectory
}
You should do something like
Iterator iter = fileDirectores.iterator();
while(iter.hasNext())
{
//Get next
//Do your check
iter.remove();
}
This leads to having three separate iterates to full fill your requirement.
It is sometimes best to define the function you're actually trying to write:
/**
* Checks to see if candidate has one string in each of classFiles, usernames and fileDirectories
*/
public boolean hasEssentialComponents(List<String> candidate) {
//Code here
}
Now, your first option has a very long maximum run time O(n^3). If you expect the function to generally fail what it means is that for each item in your three lists you are looping through the next list. Most of this is redundant, and you will have a huge performance impact if these lists are long.
The second one is subtly different, but with the same total runtime.
The third is clearly better; in this you can fail as soon as you find out that a list doesn't have a component and you never check a list for a component twice. However, Java provides some sugar that can make this easier.
public boolean hasEssentialComponents(List<String> candidates) {
//Sanity check the data
if (candidate.size() != 3) { return false; } //I'm assuming a 'good' candidate has only three items.
valid = true;
for (String candidate:candidates) {
if (valid &&
! ( check(this.classFiles, candidate)
|| check(this.usernames, candidate)
|| check(this.fileDirectories, candidate) )
)) {
valid = false;
}
}
return valid;
}
private boolean check(List<String> masterList, String candidate) {
return masterList.contains(candidate);
}
Now, I'm being unnecessarily verbose here to make sure to tease out the parts of the problem. Please note that you should use Java built in functions when possible; they're well optimized. Do not add your lists together; you're spending unnecessary time copying. Also, make each comparison only once if that is all you need: note that if you know where element in your string list should be in one of your master lists, this can be made even better.
Finally, I really recommend you write out a method signature first. It forces you to think about what you're actually trying to do.
So I take it you want to get the intersection between all three lists?
Just use the retainAll method on List.
classFiles.retainAll(usernames);
classFiles.retainAll(fileDirectories);
Now classFiles will just have the intersection between all three lists.
Can you consider to use a HashSet or HashMap to access quickly your string value (with .contains(string))?
It will eliminates the loops.
I would do this way if I understand well the problem (not sure^^)

One liner to check if element is in the list

I have been working on and off with Java/Python. Now in this situation I want to check if the element is in the list and do stuff...
Python says:
if "a" in ["a", "b", "c"]:
print "It's there!"
Does java provide any one liner for this rather than creating ArrayList / Set or similar data structure in steps and adding elements to it?
Thanks
Use Arrays.asList:
if( Arrays.asList("a","b","c").contains("a") )
There is a boolean contains(Object obj) method within the List interface.
You should be able to say:
if (list.contains("a")) {
System.out.println("It's there");
}
According to the javadoc:
boolean contains(Object o)
Returns true if this list contains the specified element.
More formally, returns true if and only if this list contains at
least one element e such that (o==null ? e==null : o.equals(e)).
In JDK7:
if ({"a", "b", "c"}.contains("a")) {
Assuming the Project Coin collections literals project goes through.
Edit: It didn't.
You could try using Strings with a separator which does not appear in any element.
if ("|a|b|c|".contains("|a|"))
I would use:
if (Stream.of("a","b","c").anyMatch("a"::equals)) {
//Code to execute
};
or:
Stream.of("a","b","c")
.filter("a"::equals)
.findAny()
.ifPresent(ignore -> /*Code to execute*/);
If he really wants a one liner without any collections, OK, he can have one:
for(String s:new String[]{"a", "b", "c")) if (s.equals("a")) System.out.println("It's there");
*smile*
(Isn't it ugly? Please, don't use it in real code)
You can use java.util.Arrays.binarySearch to find an element in an array or to check for its existence:
import java.util.Arrays;
...
char[] array = new char[] {'a', 'x', 'm'};
Arrays.sort(array);
if (Arrays.binarySearch(array, 'm') >= 0) {
System.out.println("Yes, m is there");
}
Be aware that for binarySearch to work correctly, the array needs to be sorted. Hence the call to Arrays.sort() in the example. If your data is already sorted, you don't need to do that. Thus, this isn't strictly a one-liner if you need to sort your array first. Unfortunately, Arrays.sort() does not return a reference to the array - thus it is not possible to combine sort and binarySearch (i.e. Arrays.binarySearch(Arrays.sort(myArray), key)) does not work).
If you can afford the extra allocation, using Arrays.asList() seems cleaner.
public class Itemfound{
public static void main(String args[]){
if( Arrays.asList("a","b","c").contains("a"){
System.out.println("It is here");
}
}
}
This is what you looking for. The contains() method simply checks the index of element in the list. If the index is greater than '0' than element is present in the list.
public boolean contains(Object o) {
return indexOf(o) >= 0;
}

Categories