You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@commons.apache.org by "Thomas Neidhart (JIRA)" <ji...@apache.org> on 2015/05/25 21:48:17 UTC

[jira] [Updated] (COLLECTIONS-549) Linear time implementation of retainAll for CollectionUtils

     [ https://issues.apache.org/jira/browse/COLLECTIONS-549?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Thomas Neidhart updated COLLECTIONS-549:
----------------------------------------
    Fix Version/s:     (was: 4.1)

> Linear time implementation of retainAll for CollectionUtils
> -----------------------------------------------------------
>
>                 Key: COLLECTIONS-549
>                 URL: https://issues.apache.org/jira/browse/COLLECTIONS-549
>             Project: Commons Collections
>          Issue Type: Improvement
>          Components: Collection
>    Affects Versions: 4.0
>         Environment: Ubuntu 14.04
>            Reporter: Oswaldo Olivo
>              Labels: Feature, Performance
>
> CollectionUtils provides a linear time implementation of containsAll using additional linear space.
> There is a linear time implementation of retainAll as follows:
> {code}
>  // Eliminates from coll1 all elements that are not in coll2.
>     // It runs in O(m+n) size, requiring additional O(m) space.
>     public static boolean efficientRetainAll(final Collection<?> coll1,final Collection<?> coll2) {
> 	// If coll2 is empty there are no elements to retain.
> 	if(coll2.isEmpty()) {
> 	    return coll1.removeAll(coll1);
> 	}
> 	// Simple case when we're supposed to retain all elements
> 	// in the first collection.
> 	if(coll1==coll2)
> 	    return false;
> 	
> 	// it1 iterates over coll1 and it2 iterares over coll2,
> 	// and seen contains all the elements before it2, allowing 
> 	// us to never revisit previous elements.
> 	// The algorithm iterates through it1, checks to see if we've 
> 	// already seen the current element of it1 via a Hashset 
> 	// efficient check, or traverses elements of it2 until we find 
> 	// it or it2 ends. At each iteration over it2 we add the
> 	// elements to seen to avoid revisiting items.
> 	Iterator<?> it1 = coll1.iterator();
> 	Iterator<?> it2 = coll2.iterator();
> 	HashSet<Object> seen = new HashSet<Object>();
> 	boolean changed=false;
> 	// Traverse all the elements in coll1.
> 	while(it1.hasNext()) {
> 	    final Object o=it1.next();
> 	    // If we've seen this element in coll2, keep it.
> 	    if(seen.contains(o))
> 		continue;
> 	    // Otherwise, check for its containment in coll2, while
> 	    // adding the elements to seen.
> 	    boolean contained=false;
> 	    while(it2.hasNext()) {
> 		final Object o2=it2.next();
> 		seen.add(o2);
> 		// Found the element in coll2.
> 		if(o2.equals(o)) {
> 		    contained=true;
> 		    break;
> 		}
> 	    }
> 	    // If the element was not found in coll2, remove it from it1.
> 	    if(!contained) {
> 		changed=true;
> 		it1.remove();
> 	    }
> 	}
> 	
> 	return changed;
>     }
> {code}
> Besides providing this in CollectionUtils for the user, this function could be 
> beneficial within other functions, where the existing retainAll exhibits a significant slowdown for large collections:
> 1) https://issues.apache.org/jira/browse/COLLECTIONS-534
> 2) https://issues.apache.org/jira/browse/COLLECTIONS-548



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)