001    // Copyright (c) 2001 Hursh Jain (http://www.mollypages.org) 
002    // The Molly framework is freely distributable under the terms of an
003    // MIT-style license. For details, see the molly pages web site at:
004    // http://www.mollypages.org/. Use, modify, have fun !
005    
006    package fc.util;
007    
008    import java.util.*;
009    
010    /**
011    Misc collection related utility methods.
012    
013    Inspired by similar on the web.
014    */
015    public final class C 
016    {
017    /**
018    Create an return a list from the specified args.
019    */
020    public static List list(final Object... args) 
021      {
022      //Arrays.asList is a fixed sized list backed by Args, cannot add to it
023      //return Arrays.asList(args);
024      
025      //return a proper list instead
026      final ArrayList list = new ArrayList(args.length);
027      for (int n = 0; n < args.length; n++) {
028        list.add(args[n]);
029        }
030      return list;
031      }
032    
033    /**
034    Create an return a Set from the specified args.
035    */
036    public static Set set(final Object... args) 
037      {
038      Set result = new HashSet(args.length);
039    
040      result.addAll(Arrays.asList(args));
041      return result;
042      }
043    
044    /**
045    Create an return a Map from the specified args, which are treated as key, value pairs in sequence.
046    Example:
047    <code>
048    Map map = map("a", "hello", "b", 123, "c", new int[] {4,5,6});
049    </code>
050    */
051    
052    public static Map map(final Object...objects) 
053      {
054      final Map result = new HashMap(objects.length/2);
055      if (objects.length % 2 == 1) {
056        throw new IllegalArgumentException("Need (key, value) pairs - number of args should be even!");
057      }
058      for (int n = 0; n < objects.length; n+=2)
059        {
060        result.put(objects[n], objects[n+1]);
061        }
062      return result;
063      }
064    
065    /**
066    Create an return a Map from the specified args.
067    Example:
068    <code>
069    Map map = map(e("a", "hello"), e("b", 123));
070    </code>
071    */
072    public static Map map(final Entry... entries) 
073      {
074      final Map result = new HashMap(entries.length);
075      
076      for (Entry entry : entries) {
077        result.put(entry.key, entry.val);
078        }
079      return result;
080      }
081    
082    /**
083    Alias for the e method
084    */
085    public static Entry entry(final Object key, final Object val) 
086      {
087      return new Entry(key, val);
088      }
089    
090    /**
091    Create a map entry to pass to the map method. values can be null. The key, value
092    pairs are accessed directly after they are put in the map.
093    */
094    public static Entry e(final Object key, final Object val) 
095      {
096      return new Entry(key, val);
097      }
098    
099    private static class Entry 
100      {
101      Object key;
102      Object val;
103      
104      public Entry(final Object key, final Object val) {
105        this.key = key;
106        this.val = val;
107        }
108      }
109    
110    /** 
111    Pick NON-duplicate N random items from a list. If N < number of unique items in the list, throws
112    a IllegalArgumentException. Also throws a IllegalArgumentException if not able to get unique
113    items after 16 tries (per item). To specify a different retry count (per item), use the variant
114    of this method that takes the retry parameter.
115    
116    @param count  number (N) items to choose.
117    */
118    public static Set randomNNoDuplicates(final List list, final int count) throws IllegalArgumentException
119      {
120      return randomNNoDuplicates(list, count, 16);
121      }
122            
123    /**
124    alias for the {@link #randomNNoDuplicates(List, int)} method
125    */
126    public static Set randomNNoDups(final List list, final int count) throws IllegalArgumentException
127      {
128      return randomNNoDuplicates(list, count, 16);
129      }   
130      
131    /**
132    Pick NON-duplicate N random items from a list. If N < number of unique items in the list, throws
133    a IllegalArgumentException. Also throws a IllegalArgumentException if not able to get unique
134    items after the specified (per item). 
135    
136    @param count   number (N) items to choose.
137    @param retries number of retries to get a unique random item before bailing/throwing an Exception
138    */
139    public static Set randomNNoDuplicates(final List list, final int count, final int retries) throws IllegalArgumentException
140      {
141      if (list.size() < count) {
142        throw new IllegalArgumentException("The specified list does not contain [" + count + "] items");
143        }
144            
145      final Set set = new HashSet();
146      set.addAll(list);
147      
148      //these many unique items exist ?
149      if (set.size() < count) {
150        throw new IllegalArgumentException("The specified list does not contain [" + count + "] unique items");
151        }
152      set.clear();
153      Random r = new Random();
154      
155      for (int n = 0; n < count; n++) 
156        {
157        Object item = list.get(r.nextInt(list.size()));
158        int tries = 0;
159        while (set.contains(item)) 
160          {
161          item = list.get(r.nextInt(list.size()));
162          tries++;
163          if (tries > retries) {
164            throw new IllegalArgumentException("Too many tries to get a unique item");
165            }
166          }
167        set.add(item);
168        }
169      return set;
170      }
171    
172    /** unbox and return 0 if null */
173    public static short unbox(Short s) {
174      if (s == null) return 0;
175      else return s;
176      }
177    
178    /** unbox and return 0 if null */
179    public static short unboxShort(Object s) {
180      return unbox((Short)s);
181      }
182    
183    /** unbox and return 0 if null */
184    public static int unbox(Integer i) {
185      if (i == null) return 0;
186      else return i;
187      }
188    
189    /** unbox and return 0 if null */
190    public static int unboxInt(Object i) {
191      return unbox((Integer)i);
192      }
193      
194    /** unbox and return 0 if null */
195    public static long unbox(Long l) {
196      if (l == null) return 0;
197      else return l;
198      }
199    
200    /** unbox and return 0 if null */
201    public static long unboxLong(Object i) {
202      return unbox((Long)i);
203      }
204      
205    /** unbox and return 0 if null */
206    public static double unbox(Double d) {
207      if (d == null) return 0;
208      else return d;
209      }
210    
211    /** unbox and return 0 if null */
212    public static double unboxDouble(Object d) {
213      return unbox((Double)d);
214      }
215      
216    /** unbox and return '0' if null */
217    public static char unbox(Character c) {
218      if (c == null) return '0';
219      else return c;
220      }
221    
222    /** unbox and return '0' if null */
223    public static char unboxChar(Object c) {
224      return unbox((Character)c);
225      }
226      
227    /** unbox and return false if null */
228    public static boolean unbox(Boolean b) {
229      if (b == null) return false;
230      else return b;
231      }
232    
233    /** unbox and return false if null */
234    public static boolean unboxBool(Object b) {
235      return unbox((Boolean)b);
236      }
237    
238    /** unbox and return false if null */
239    public static boolean unboxBoolean(Object b) {
240      return unbox((Boolean)b);
241      }
242    
243    
244    /** 
245    Returns true if the specified collection is null or empty.
246    **/
247    public static boolean nullOrEmpty(Collection c) 
248      {
249      return c != null && c.size() == 0;
250      }
251    
252    
253    public static void main(String args[]) 
254      {
255      List list = list("a", "b", 1);
256      System.out.println(list);
257      
258      Set set = set("a", "b", "b", "c", 1);
259      System.out.println(set);
260      
261      Map map = map(entry("a", 123), entry("b", new Object()), e(1, "1"), e(2, null));
262      System.out.println(map);
263    
264      Map map2 = map("a", "hello", "b", 123, "c", new int[] {4,5,6}, "s", null);
265      System.out.println(map2);
266    
267      //traditional way
268      String s = (String) map2.get("s");
269      System.out.println("string:" + s);
270      
271      //unbox util
272      int i = unboxInt(map2.get("b"));
273      System.out.println("int:" + i);
274      
275      //any null value can be unboxed at any type
276      int i2 = unboxInt(map2.get("s"));
277      System.out.println("int:" + i2);
278    
279      //any null value can be unboxed at any type
280      boolean b = unboxBool(map2.get("s"));
281      System.out.println("boolean: " + b);
282      
283      List list2 = list("a", "b", "a", "c", "d", "c", "g");
284      System.out.println(randomNNoDuplicates(list2, 3));
285    
286      System.out.println("==Exception expected===");
287      try {
288        list2 = list("a", "b");
289        System.out.println(randomNNoDuplicates(list2, 3));
290        }
291      catch (Exception e) {
292        System.out.println(e);
293        }
294      System.out.println("==end Exception expected===");
295    
296      list2 = list("a", "b", "c");
297      System.out.println(randomNNoDuplicates(list2, 3));
298    
299      for (int n = 0; n < 300; n++) {
300        list2.add("x");
301        }
302    
303      Collections.shuffle(list2);
304      
305      System.out.println("==should more than likely throw a retry count exception==");
306      try {
307        System.out.println(randomNNoDuplicates(list2, 3));
308        }
309      catch (Exception e) {
310        System.out.println(e);
311        }
312    
313      System.out.println("==should more than likely NOT throw a retry count exception (trying 1000 times per item) ==");
314      System.out.println(randomNNoDuplicates(list2, 3, 1000));
315      }
316    }
317