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
006package fc.util;
007
008import java.util.*;
009
010/**
011Misc collection related utility methods.
012
013Inspired by similar on the web.
014*/
015public final class C 
016{
017/**
018Create an return a list from the specified args.
019*/
020public 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/**
034Create an return a Set from the specified args.
035*/
036public 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/**
045Create an return a Map from the specified args, which are treated as key, value pairs in sequence.
046Example:
047<code>
048Map map = map("a", "hello", "b", 123, "c", new int[] {4,5,6});
049</code>
050*/
051
052public 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/**
066Create an return a Map from the specified args.
067Example:
068<code>
069Map map = map(e("a", "hello"), e("b", 123));
070</code>
071*/
072public 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/**
083Alias for the e method
084*/
085public static Entry entry(final Object key, final Object val) 
086  {
087  return new Entry(key, val);
088  }
089
090/**
091Create a map entry to pass to the map method. values can be null. The key, value
092pairs are accessed directly after they are put in the map.
093*/
094public static Entry e(final Object key, final Object val) 
095  {
096  return new Entry(key, val);
097  }
098
099private 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/** 
111Pick NON-duplicate N random items from a list. If N < number of unique items in the list, throws
112a IllegalArgumentException. Also throws a IllegalArgumentException if not able to get unique
113items after 16 tries (per item). To specify a different retry count (per item), use the variant
114of this method that takes the retry parameter.
115
116@param count  number (N) items to choose.
117*/
118public static Set randomNNoDuplicates(final List list, final int count) throws IllegalArgumentException
119  {
120  return randomNNoDuplicates(list, count, 16);
121  }
122        
123/**
124alias for the {@link #randomNNoDuplicates(List, int)} method
125*/
126public static Set randomNNoDups(final List list, final int count) throws IllegalArgumentException
127  {
128  return randomNNoDuplicates(list, count, 16);
129  }   
130  
131/**
132Pick NON-duplicate N random items from a list. If N < number of unique items in the list, throws
133a IllegalArgumentException. Also throws a IllegalArgumentException if not able to get unique
134items 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*/
139public 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 */
173public static short unbox(Short s) {
174  if (s == null) return 0;
175  else return s;
176  }
177
178/** unbox and return 0 if null */
179public static short unboxShort(Object s) {
180  return unbox((Short)s);
181  }
182
183/** unbox and return 0 if null */
184public static int unbox(Integer i) {
185  if (i == null) return 0;
186  else return i;
187  }
188
189/** unbox and return 0 if null */
190public static int unboxInt(Object i) {
191  return unbox((Integer)i);
192  }
193  
194/** unbox and return 0 if null */
195public static long unbox(Long l) {
196  if (l == null) return 0;
197  else return l;
198  }
199
200/** unbox and return 0 if null */
201public static long unboxLong(Object i) {
202  return unbox((Long)i);
203  }
204  
205/** unbox and return 0 if null */
206public static double unbox(Double d) {
207  if (d == null) return 0;
208  else return d;
209  }
210
211/** unbox and return 0 if null */
212public static double unboxDouble(Object d) {
213  return unbox((Double)d);
214  }
215  
216/** unbox and return '0' if null */
217public static char unbox(Character c) {
218  if (c == null) return '0';
219  else return c;
220  }
221
222/** unbox and return '0' if null */
223public static char unboxChar(Object c) {
224  return unbox((Character)c);
225  }
226  
227/** unbox and return false if null */
228public static boolean unbox(Boolean b) {
229  if (b == null) return false;
230  else return b;
231  }
232
233/** unbox and return false if null */
234public static boolean unboxBool(Object b) {
235  return unbox((Boolean)b);
236  }
237
238/** unbox and return false if null */
239public static boolean unboxBoolean(Object b) {
240  return unbox((Boolean)b);
241  }
242
243
244/** 
245Returns true if the specified collection is null or empty.
246**/
247public static boolean nullOrEmpty(Collection c) 
248  {
249  return c != null && c.size() == 0;
250  }
251
252
253public 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