diff --git a/src/changes/changes.xml b/src/changes/changes.xml index cededa04e..d8acf73ec 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -51,6 +51,9 @@ If the output is not quite correct, check for invisible trailing spaces! + + Add mode function to Frequency class. + Fixed "MathArrays.linearCombination" when array length is 1. diff --git a/src/main/java/org/apache/commons/math3/stat/Frequency.java b/src/main/java/org/apache/commons/math3/stat/Frequency.java index f15565079..ff5d20adf 100644 --- a/src/main/java/org/apache/commons/math3/stat/Frequency.java +++ b/src/main/java/org/apache/commons/math3/stat/Frequency.java @@ -18,10 +18,13 @@ package org.apache.commons.math3.stat; import java.io.Serializable; import java.text.NumberFormat; +import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.Comparator; +import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.TreeMap; import org.apache.commons.math3.exception.MathIllegalArgumentException; @@ -493,6 +496,39 @@ public class Frequency implements Serializable { return getCumPct(Character.valueOf(v)); } + /** + * Returns the mode value(s) in comparator order. + * + * @return a list containing the value(s) which appear most often. + * @since 3.3 + */ + public List> getMode() { + long mostPopular = 0; // frequencies are always positive + + // Get the max count first, so we avoid having to recreate the List each time + for(Long l : freqTable.values()) { + long frequency = l.longValue(); + if (frequency > mostPopular) { + mostPopular = frequency; + } + } + + List> modeList = new ArrayList>(); + for (Entry, Long> ent : freqTable.entrySet()) { + long frequency = ent.getValue().longValue(); + if (frequency == mostPopular) { + modeList.add(ent.getKey()); +// Alternatively, to avoid scanning the entries twice, keep recreating the set +// To use this approach, comment out the values() scan loop above and uncomment below +// } else if (frequency > mostPopular) { +// modeList.clear(); // the previous List is obsolete +// modeList.add(ent.getKey()); +// mostPopular = frequency; + } + } + return modeList; + } + //---------------------------------------------------------------------------------------------- /** diff --git a/src/test/java/org/apache/commons/math3/stat/FrequencyTest.java b/src/test/java/org/apache/commons/math3/stat/FrequencyTest.java index 7e59f16ed..edf61788c 100644 --- a/src/test/java/org/apache/commons/math3/stat/FrequencyTest.java +++ b/src/test/java/org/apache/commons/math3/stat/FrequencyTest.java @@ -334,18 +334,28 @@ public final class FrequencyTest { Assert.assertEquals(1, f.getCount(THREEE)); } -// @Test -// public void testMode() { -// Assert.assertEquals(0, f.getMode().size()); -// f.addValue("1"); -// Assert.assertEquals(1, f.getMode().size()); -// f.addValue("2"); -// Assert.assertEquals(2, f.getMode().size()); -// Assert.assertTrue(f.getMode().contains("1")); -// Assert.assertTrue(f.getMode().contains("2")); -// f.addValue("2"); -// Assert.assertEquals(1, f.getMode().size()); -// Assert.assertFalse(f.getMode().contains("1")); -// Assert.assertTrue(f.getMode().contains("2")); -// } + @Test + public void testMode() { + List> mode; + mode = f.getMode(); + Assert.assertEquals(0, mode.size()); + + f.addValue("3"); + mode = f.getMode(); + Assert.assertEquals(1, mode.size()); + Assert.assertEquals("3", mode.get(0)); + + f.addValue("2"); + mode = f.getMode(); + Assert.assertEquals(2, mode.size()); + Assert.assertEquals("2", mode.get(0)); + Assert.assertEquals("3",mode.get(1)); + + f.addValue("2"); + mode = f.getMode(); + Assert.assertEquals(1, mode.size()); + Assert.assertEquals("2", mode.get(0)); + Assert.assertFalse(mode.contains("1")); + Assert.assertTrue(mode.contains("2")); + } }