commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mben...@apache.org
Subject svn commit: r1147522 - in /commons/proper/lang/trunk/src: main/java/org/apache/commons/lang3/ObjectUtils.java test/java/org/apache/commons/lang3/ObjectUtilsTest.java
Date Sun, 17 Jul 2011 04:22:52 GMT
Author: mbenson
Date: Sun Jul 17 04:22:51 2011
New Revision: 1147522

URL: http://svn.apache.org/viewvc?rev=1147522&view=rev
Log:
[LANG-723] Add mode and median Comparable... methods to ObjectUtils

Modified:
    commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/ObjectUtils.java
    commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/ObjectUtilsTest.java

Modified: commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/ObjectUtils.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/ObjectUtils.java?rev=1147522&r1=1147521&r2=1147522&view=diff
==============================================================================
--- commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/ObjectUtils.java (original)
+++ commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/ObjectUtils.java Sun
Jul 17 04:22:51 2011
@@ -20,8 +20,14 @@ import java.io.Serializable;
 import java.lang.reflect.Array;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TreeSet;
 
 import org.apache.commons.lang3.exception.CloneFailedException;
+import org.apache.commons.lang3.mutable.MutableInt;
 
 /**
  * <p>Operations on {@code Object}.</p>
@@ -410,6 +416,82 @@ public class ObjectUtils {
         return c1.compareTo(c2);
     }
 
+    /**
+     * Find the "best guess" middle value among comparables. If there is an even
+     * number of total values, the lower of the two middle values will be returned.
+     * @param <T> type of values processed by this method
+     * @param items to compare
+     * @return T at middle position
+     * @throws NullPointerException if items is {@code null}
+     * @throws IllegalArgumentException if items is empty or contains {@code null} values
+     */
+    public static <T extends Comparable<? super T>> T median(T... items) {
+        Validate.notEmpty(items);
+        Validate.noNullElements(items);
+        TreeSet<T> sort = new TreeSet<T>();
+        Collections.addAll(sort, items);
+        @SuppressWarnings("unchecked") //we know all items added were T instances
+        T result = (T) sort.toArray()[(sort.size() - 1) / 2];
+        return result;
+    }
+
+    /**
+     * Find the "best guess" middle value among comparables. If there is an even
+     * number of total values, the lower of the two middle values will be returned.
+     * @param <T> type of values processed by this method
+     * @param comparator to use for comparisons
+     * @param items to compare
+     * @return T at middle position
+     * @throws NullPointerException if items or comparator is {@code null}
+     * @throws IllegalArgumentException if items is empty or contains {@code null} values
+     */
+    public static <T> T median(Comparator<T> comparator, T... items) {
+        Validate.notEmpty(items, "null/empty items");
+        Validate.noNullElements(items);
+        Validate.notNull(comparator, "null comparator");
+        TreeSet<T> sort = new TreeSet<T>(comparator);
+        Collections.addAll(sort, items);
+        @SuppressWarnings("unchecked") //we know all items added were T instances
+        T result = (T) sort.toArray()[(sort.size() - 1) / 2];
+        return result;
+    }
+
+    // Mode
+    //-----------------------------------------------------------------------
+    /**
+     * Find the most frequently occurring item.
+     * 
+     * @param <T>
+     * @param items to check
+     * @return most populous T, {@code null} if non-unique or no items supplied
+     */
+    public static <T> T mode(T... items) {
+        if (ArrayUtils.isNotEmpty(items)) {
+            HashMap<T, MutableInt> occurrences = new HashMap<T, MutableInt>(items.length);
+            for (T t : items) {
+                MutableInt count = occurrences.get(t);
+                if (count == null) {
+                    occurrences.put(t, new MutableInt(1));
+                } else {
+                    count.increment();
+                }
+            }
+            T result = null;
+            int max = 0;
+            for (Map.Entry<T, MutableInt> e : occurrences.entrySet()) {
+                int cmp = e.getValue().intValue();
+                if (cmp == max) {
+                    result = null;
+                } else if (cmp > max) {
+                    max = cmp;
+                    result = e.getKey();
+                }
+            }
+            return result;
+        }
+        return null;
+    }
+
     // cloning
     //-----------------------------------------------------------------------
     /**

Modified: commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/ObjectUtilsTest.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/ObjectUtilsTest.java?rev=1147522&r1=1147521&r2=1147522&view=diff
==============================================================================
--- commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/ObjectUtilsTest.java
(original)
+++ commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/ObjectUtilsTest.java
Sun Jul 17 04:22:51 2011
@@ -23,6 +23,7 @@ import java.lang.reflect.Modifier;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
+import java.util.Comparator;
 import java.util.Date;
 import java.util.List;
 
@@ -288,6 +289,75 @@ public class ObjectUtilsTest {
         assertEquals("one two true",  -1, ObjectUtils.compare(one, two, true));
     }
 
+    @Test
+    public void testMedian() {
+        assertEquals("foo", ObjectUtils.median("foo"));
+        assertEquals("bar", ObjectUtils.median("foo", "bar"));
+        assertEquals("baz", ObjectUtils.median("foo", "bar", "baz"));
+        assertEquals("baz", ObjectUtils.median("foo", "bar", "baz", "blah"));
+        assertEquals("blah", ObjectUtils.median("foo", "bar", "baz", "blah", "wah"));
+        assertEquals(Integer.valueOf(5),
+            ObjectUtils.median(Integer.valueOf(1), Integer.valueOf(5), Integer.valueOf(10)));
+        assertEquals(
+            Integer.valueOf(7),
+            ObjectUtils.median(Integer.valueOf(5), Integer.valueOf(6), Integer.valueOf(7),
Integer.valueOf(8),
+                Integer.valueOf(9)));
+        assertEquals(Integer.valueOf(6),
+            ObjectUtils.median(Integer.valueOf(5), Integer.valueOf(6), Integer.valueOf(7),
Integer.valueOf(8)));
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testMedian_nullItems() {
+        ObjectUtils.median((String[]) null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testMedian_emptyItems() {
+        ObjectUtils.<String> median();
+    }
+
+    @Test
+    public void testComparatorMedian() {
+        CharSequenceComparator cmp = new CharSequenceComparator();
+        NonComparableCharSequence foo = new NonComparableCharSequence("foo");
+        NonComparableCharSequence bar = new NonComparableCharSequence("bar");
+        NonComparableCharSequence baz = new NonComparableCharSequence("baz");
+        NonComparableCharSequence blah = new NonComparableCharSequence("blah");
+        NonComparableCharSequence wah = new NonComparableCharSequence("wah");
+        assertSame(foo, ObjectUtils.median(cmp, foo));
+        assertSame(bar, ObjectUtils.median(cmp, foo, bar));
+        assertSame(baz, ObjectUtils.median(cmp, foo, bar, baz));
+        assertSame(baz, ObjectUtils.median(cmp, foo, bar, baz, blah));
+        assertSame(blah, ObjectUtils.median(cmp, foo, bar, baz, blah, wah));
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testComparatorMedian_nullComparator() {
+        ObjectUtils.median((Comparator<CharSequence>) null, new NonComparableCharSequence("foo"));
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testComparatorMedian_nullItems() {
+        ObjectUtils.median(new CharSequenceComparator(), (CharSequence[]) null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testComparatorMedian_emptyItems() {
+        ObjectUtils.median(new CharSequenceComparator());
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testMode() {
+        assertNull(ObjectUtils.mode((Object[]) null));
+        assertNull(ObjectUtils.mode());
+        assertNull(ObjectUtils.mode("foo", "bar", "baz"));
+        assertNull(ObjectUtils.mode("foo", "bar", "baz", "foo", "bar"));
+        assertEquals("foo", ObjectUtils.mode("foo", "bar", "baz", "foo"));
+        assertEquals(Integer.valueOf(9),
+            ObjectUtils.mode("foo", "bar", "baz", Integer.valueOf(9), Integer.valueOf(10),
Integer.valueOf(9)));
+    }
+
     /**
      * Tests {@link ObjectUtils#clone(Object)} with a cloneable object.
      */
@@ -396,4 +466,43 @@ public class ObjectUtilsTest {
         }
     }
 
+    static final class NonComparableCharSequence implements CharSequence {
+        final String value;
+
+        /**
+         * Create a new NonComparableCharSequence instance.
+         *
+         * @param value
+         */
+        public NonComparableCharSequence(String value) {
+            super();
+            Validate.notNull(value);
+            this.value = value;
+        }
+
+        public char charAt(int arg0) {
+            return value.charAt(arg0);
+        }
+
+        public int length() {
+            return value.length();
+        }
+
+        public CharSequence subSequence(int arg0, int arg1) {
+            return value.subSequence(arg0, arg1);
+        }
+
+        @Override
+        public String toString() {
+            return value;
+        }
+    }
+
+    static final class CharSequenceComparator implements Comparator<CharSequence> {
+
+        public int compare(CharSequence o1, CharSequence o2) {
+            return o1.toString().compareTo(o2.toString());
+        }
+
+    }
 }



Mime
View raw message