Coverage Report - org.codehaus.plexus.util.CollectionUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
CollectionUtils
86%
52/60
76%
26/34
4.429
 
 1  
 package org.codehaus.plexus.util;
 2  
 
 3  
 /*
 4  
  * Copyright The Codehaus Foundation.
 5  
  *
 6  
  * Licensed under the Apache License, Version 2.0 (the "License");
 7  
  * you may not use this file except in compliance with the License.
 8  
  * You may obtain a copy of the License at
 9  
  *
 10  
  *     http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing, software
 13  
  * distributed under the License is distributed on an "AS IS" BASIS,
 14  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15  
  * See the License for the specific language governing permissions and
 16  
  * limitations under the License.
 17  
  */
 18  
 
 19  
 import java.util.ArrayList;
 20  
 import java.util.Collection;
 21  
 import java.util.HashMap;
 22  
 import java.util.HashSet;
 23  
 import java.util.Iterator;
 24  
 import java.util.List;
 25  
 import java.util.Map;
 26  
 import java.util.NoSuchElementException;
 27  
 import java.util.Set;
 28  
 
 29  
 /**
 30  
  * @author <a href="mailto:olamy@codehaus.org">olamy</a>
 31  
  * @version $Id$
 32  
  */
 33  0
 public class CollectionUtils
 34  
 {
 35  
     // ----------------------------------------------------------------------
 36  
     // Static methods that can probably be moved to a real util class.
 37  
     // ----------------------------------------------------------------------
 38  
 
 39  
     /**
 40  
      * Take a dominant and recessive Map and merge the key:value pairs where the recessive Map may add key:value pairs
 41  
      * to the dominant Map but may not override any existing key:value pairs. If we have two Maps, a dominant and
 42  
      * recessive, and their respective keys are as follows: dominantMapKeys = { a, b, c, d, e, f } recessiveMapKeys = {
 43  
      * a, b, c, x, y, z } Then the result should be the following: resultantKeys = { a, b, c, d, e, f, x, y, z }
 44  
      *
 45  
      * @param dominantMap Dominant Map.
 46  
      * @param recessiveMap Recessive Map.
 47  
      * @return The result map with combined dominant and recessive values.
 48  
      */
 49  
     public static <K, V> Map<K, V> mergeMaps( Map<K, V> dominantMap, Map<K, V> recessiveMap )
 50  
     {
 51  
 
 52  11
         if ( dominantMap == null && recessiveMap == null )
 53  
         {
 54  0
             return null;
 55  
         }
 56  
 
 57  11
         if ( dominantMap != null && recessiveMap == null )
 58  
         {
 59  0
             return dominantMap;
 60  
         }
 61  
 
 62  11
         if ( dominantMap == null )
 63  
         {
 64  0
             return recessiveMap;
 65  
         }
 66  
 
 67  11
         Map<K, V> result = new HashMap<K, V>();
 68  
 
 69  
         // Grab the keys from the dominant and recessive maps.
 70  11
         Set<K> dominantMapKeys = dominantMap.keySet();
 71  11
         Set<K> recessiveMapKeys = recessiveMap.keySet();
 72  
 
 73  
         // Create the set of keys that will be contributed by the
 74  
         // recessive Map by subtracting the intersection of keys
 75  
         // from the recessive Map's keys.
 76  11
         Collection<K> contributingRecessiveKeys =
 77  
             CollectionUtils.subtract( recessiveMapKeys,
 78  
                                       CollectionUtils.intersection( dominantMapKeys, recessiveMapKeys ) );
 79  
 
 80  11
         result.putAll( dominantMap );
 81  
 
 82  
         // Now take the keys we just found and extract the values from
 83  
         // the recessiveMap and put the key:value pairs into the dominantMap.
 84  11
         for ( K key : contributingRecessiveKeys )
 85  
         {
 86  15
             result.put( key, recessiveMap.get( key ) );
 87  15
         }
 88  
 
 89  11
         return result;
 90  
     }
 91  
 
 92  
     /**
 93  
      * Take a series of <code>Map</code>s and merge them where the ordering of the array from 0..n is the dominant
 94  
      * order.
 95  
      *
 96  
      * @param maps An array of Maps to merge.
 97  
      * @return Map The result Map produced after the merging process.
 98  
      */
 99  
     public static <K, V> Map<K, V> mergeMaps( Map<K, V>[] maps )
 100  
     {
 101  
         Map<K, V> result;
 102  
 
 103  7
         if ( maps.length == 0 )
 104  
         {
 105  1
             result = null;
 106  
         }
 107  6
         else if ( maps.length == 1 )
 108  
         {
 109  1
             result = maps[0];
 110  
         }
 111  
         else
 112  
         {
 113  5
             result = mergeMaps( maps[0], maps[1] );
 114  
 
 115  10
             for ( int i = 2; i < maps.length; i++ )
 116  
             {
 117  5
                 result = mergeMaps( result, maps[i] );
 118  
             }
 119  
         }
 120  
 
 121  7
         return result;
 122  
     }
 123  
 
 124  
     /**
 125  
      * Returns a {@link Collection} containing the intersection of the given {@link Collection}s.
 126  
      * <p>
 127  
      * The cardinality of each element in the returned {@link Collection} will be equal to the minimum of the
 128  
      * cardinality of that element in the two given {@link Collection}s.
 129  
      *
 130  
      * @param a The first collection
 131  
      * @param b The second collection
 132  
      * @see Collection#retainAll
 133  
      * @return The intersection of a and b, never null
 134  
      */
 135  
     public static <E> Collection<E> intersection( final Collection<E> a, final Collection<E> b )
 136  
     {
 137  11
         ArrayList<E> list = new ArrayList<E>();
 138  11
         Map<E, Integer> mapa = getCardinalityMap( a );
 139  11
         Map<E, Integer> mapb = getCardinalityMap( b );
 140  11
         Set<E> elts = new HashSet<E>( a );
 141  11
         elts.addAll( b );
 142  11
         for ( E obj : elts )
 143  
         {
 144  64
             for ( int i = 0, m = Math.min( getFreq( obj, mapa ), getFreq( obj, mapb ) ); i < m; i++ )
 145  
             {
 146  15
                 list.add( obj );
 147  
             }
 148  49
         }
 149  11
         return list;
 150  
     }
 151  
 
 152  
     /**
 153  
      * Returns a {@link Collection} containing <tt><i>a</i> - <i>b</i></tt>. The cardinality of each element <i>e</i> in
 154  
      * the returned {@link Collection} will be the cardinality of <i>e</i> in <i>a</i> minus the cardinality of <i>e</i>
 155  
      * in <i>b</i>, or zero, whichever is greater.
 156  
      *
 157  
      * @param a The start collection
 158  
      * @param b The collection that will be subtracted
 159  
      * @see Collection#removeAll
 160  
      * @return The result of the subtraction
 161  
      */
 162  
     public static <T> Collection<T> subtract( final Collection<T> a, final Collection<T> b )
 163  
     {
 164  11
         ArrayList<T> list = new ArrayList<T>( a );
 165  11
         for ( T aB : b )
 166  
         {
 167  15
             list.remove( aB );
 168  15
         }
 169  11
         return list;
 170  
     }
 171  
 
 172  
     /**
 173  
      * Returns a {@link Map} mapping each unique element in the given {@link Collection} to an {@link Integer}
 174  
      * representing the number of occurrences of that element in the {@link Collection}. An entry that maps to
 175  
      * <tt>null</tt> indicates that the element does not appear in the given {@link Collection}.
 176  
      * 
 177  
      * @param col The collection to count cardinalities for
 178  
      * @return A map of counts, indexed on each element in the collection
 179  
      */
 180  
     public static <E> Map<E, Integer> getCardinalityMap( final Collection<E> col )
 181  
     {
 182  22
         HashMap<E, Integer> count = new HashMap<E, Integer>();
 183  22
         for ( E obj : col )
 184  
         {
 185  64
             Integer c = count.get( obj );
 186  64
             if ( null == c )
 187  
             {
 188  64
                 count.put( obj, 1 );
 189  
             }
 190  
             else
 191  
             {
 192  0
                 count.put( obj, c + 1 );
 193  
             }
 194  64
         }
 195  22
         return count;
 196  
     }
 197  
 
 198  
     public static <E> List<E> iteratorToList( Iterator<E> it )
 199  
     {
 200  2
         if ( it == null )
 201  
         {
 202  0
             throw new NullPointerException( "it cannot be null." );
 203  
         }
 204  
 
 205  2
         List<E> list = new ArrayList<E>();
 206  
 
 207  5
         while ( it.hasNext() )
 208  
         {
 209  3
             list.add( it.next() );
 210  
         }
 211  
 
 212  2
         return list;
 213  
     }
 214  
 
 215  
     // ----------------------------------------------------------------------
 216  
     //
 217  
     // ----------------------------------------------------------------------
 218  
 
 219  
     private static <E> int getFreq( final E obj, final Map<E, Integer> freqMap )
 220  
     {
 221  
         try
 222  
         {
 223  98
             Integer o = freqMap.get( obj );
 224  98
             if ( o != null ) // minimize NullPointerExceptions
 225  
             {
 226  64
                 return o;
 227  
             }
 228  
         }
 229  0
         catch ( NullPointerException ignore )
 230  
         {
 231  
         }
 232  0
         catch ( NoSuchElementException ignore )
 233  
         {
 234  34
         }
 235  34
         return 0;
 236  
     }
 237  
 }