diff --git a/core/src/processing/data/FloatDict.java b/core/src/processing/data/FloatDict.java index 3e5e29b73..0e6873732 100644 --- a/core/src/processing/data/FloatDict.java +++ b/core/src/processing/data/FloatDict.java @@ -365,21 +365,106 @@ public class FloatDict { } + private void checkMinMax(String functionName) { + if (count == 0) { + String msg = + String.format("Cannot use %s() on an empty %s.", + functionName, getClass().getSimpleName()); + throw new RuntimeException(msg); + } + } + + + /** + * @webref floatlist:method + * @brief Return the smallest value + */ + public int minIndex() { + checkMinMax("minIndex"); + // Will still return NaN if there is 1 or more entries, and they're all NaN + float m = Float.NaN; + int mi = -1; + for (int i = 0; i < count; i++) { + // find one good value to start + if (values[i] == values[i]) { + m = values[i]; + mi = i; + + // calculate the rest + for (int j = i+1; j < count; j++) { + float d = values[j]; + if (!Float.isNaN(d) && (d < m)) { + m = values[j]; + mi = j; + } + } + break; + } + } + return mi; + } + + + public String minKey() { + checkMinMax("minKey"); + return keys[minIndex()]; + } + + + public float minValue() { + checkMinMax("minValue"); + return values[minIndex()]; + } + + + /** + * @webref floatlist:method + * @brief Return the largest value + */ + public int maxIndex() { + checkMinMax("maxIndex"); + // Will still return NaN if there is 1 or more entries, and they're all NaN + float m = Float.NaN; + int mi = -1; + for (int i = 0; i < count; i++) { + // find one good value to start + if (values[i] == values[i]) { + m = values[i]; + mi = i; + + // calculate the rest + for (int j = i+1; j < count; j++) { + float d = values[j]; + if (!Float.isNaN(d) && (d > m)) { + m = values[j]; + mi = j; + } + } + break; + } + } + return mi; + } + + + public String maxKey() { + checkMinMax("maxKey"); + return keys[maxIndex()]; + } + + + public float maxValue() { + checkMinMax("maxValue"); + return values[maxIndex()]; + } + + public int index(String what) { Integer found = indices.get(what); return (found == null) ? -1 : found.intValue(); } -// public void add(String key) { -// if (index(key) != -1) { -// throw new IllegalArgumentException("Use inc() to increment an entry, " + -// "add() is for adding a new key"); -// } -// add(key, 0); -// } - - protected void create(String what, float much) { if (count == keys.length) { keys = PApplet.expand(keys); @@ -396,12 +481,17 @@ public class FloatDict { * @webref floatdict:method * @brief Remove a key/value pair */ - public void remove(String key) { - removeIndex(index(key)); + public int remove(String key) { + int index = index(key); + if (index != -1) { + removeIndex(index); + } + return index; } - public void removeIndex(int index) { + public String removeIndex(int index) { + String key = keys[index]; //System.out.println("index is " + which + " and " + keys[which]); indices.remove(keys[index]); for (int i = index; i < count-1; i++) { @@ -412,6 +502,7 @@ public class FloatDict { count--; keys[count] = null; values[count] = 0; + return key; } diff --git a/core/src/processing/data/FloatList.java b/core/src/processing/data/FloatList.java index 19aa9dc87..6e812d1b0 100644 --- a/core/src/processing/data/FloatList.java +++ b/core/src/processing/data/FloatList.java @@ -132,41 +132,38 @@ public class FloatList implements Iterable { * @webref floatlist:method * @brief Remove an element from the specified index */ - public void remove(int index) { + public float remove(int index) { + float entry = data[index]; // int[] outgoing = new int[count - 1]; // System.arraycopy(data, 0, outgoing, 0, index); // count--; // System.arraycopy(data, index + 1, outgoing, 0, count - index); // data = outgoing; + // For most cases, this actually appears to be faster + // than arraycopy() on an array copying into itself. for (int i = index; i < count-1; i++) { data[i] = data[i+1]; } count--; + return entry; } - /** Remove the first instance of a particular value */ - public boolean removeValue(float value) { - if (Float.isNaN(value)) { - for (int i = 0; i < count; i++) { - if (Float.isNaN(data[i])) { - remove(i); - return true; - } - } - } else { - int index = index(value); - if (index != -1) { - remove(index); - return true; - } + // Remove the first instance of a particular value, + // and return the index at which it was found. + public int removeValue(int value) { + int index = index(value); + if (index != -1) { + remove(index); + return index; } - return false; + return -1; } - /** Remove all instances of a particular value */ - public boolean removeValues(float value) { + // Remove all instances of a particular value, + // and return the number of values found and removed + public int removeValues(int value) { int ii = 0; if (Float.isNaN(value)) { for (int i = 0; i < count; i++) { @@ -181,11 +178,9 @@ public class FloatList implements Iterable { } } } - if (count == ii) { - return false; - } + int removed = count - ii; count = ii; - return true; + return removed; } @@ -387,15 +382,6 @@ public class FloatList implements Iterable { } - // !!! TODO this is not yet correct, because it's not being reset when - // the rest of the entries are changed -// protected void cacheIndices() { -// indexCache = new HashMap(); -// for (int i = 0; i < count; i++) { -// indexCache.put(data[i], i); -// } -// } - /** * @webref floatlist:method * @brief Check if a number is a part of the list @@ -418,11 +404,6 @@ public class FloatList implements Iterable { } - // doesn't really make sense with float.. use add() if you need it -// public void increment(int index) { -// data[index]++; -// } - /** * @webref floatlist:method * @brief Add to a value @@ -431,6 +412,7 @@ public class FloatList implements Iterable { data[index] += amount; } + /** * @webref floatlist:method * @brief Subtract from a value @@ -439,6 +421,7 @@ public class FloatList implements Iterable { data[index] -= amount; } + /** * @webref floatlist:method * @brief Multiply a value @@ -447,6 +430,7 @@ public class FloatList implements Iterable { data[index] *= amount; } + /** * @webref floatlist:method * @brief Divide a value @@ -455,64 +439,86 @@ public class FloatList implements Iterable { data[index] /= amount; } + + private void checkMinMax(String functionName) { + if (count == 0) { + String msg = + String.format("Cannot use %s() on an empty %s.", + functionName, getClass().getSimpleName()); + throw new RuntimeException(msg); + } + } + + /** * @webref floatlist:method * @brief Return the smallest value */ public float min() { - if (count == 0) { - throw new ArrayIndexOutOfBoundsException("Cannot use min() on IntList of length 0."); - } - if (data.length == 0) { - return Float.NaN; - } + checkMinMax("min"); + int index = minIndex(); + return index == -1 ? Float.NaN : data[index]; + } + + + public int minIndex() { + checkMinMax("minIndex"); float m = Float.NaN; - for (int i = 0; i < data.length; i++) { + int mi = -1; + for (int i = 0; i < count; i++) { // find one good value to start if (data[i] == data[i]) { m = data[i]; + mi = i; // calculate the rest - for (int j = i+1; j < data.length; j++) { + for (int j = i+1; j < count; j++) { float d = data[j]; if (!Float.isNaN(d) && (d < m)) { m = data[j]; + mi = j; } } break; } } - return m; + return mi; } + /** * @webref floatlist:method * @brief Return the largest value */ public float max() { - if (count == 0) { - throw new ArrayIndexOutOfBoundsException("Cannot use max() on IntList of length 0."); - } - if (data.length == 0) { - return Float.NaN; - } + checkMinMax("max"); + int index = maxIndex(); + return index == -1 ? Float.NaN : data[index]; + } + + + public int maxIndex() { + checkMinMax("maxIndex"); float m = Float.NaN; - for (int i = 0; i < data.length; i++) { + int mi = -1; + for (int i = 0; i < count; i++) { // find one good value to start if (data[i] == data[i]) { m = data[i]; + mi = i; // calculate the rest - for (int j = i+1; j < data.length; j++) { + for (int j = i+1; j < count; j++) { float d = data[j]; if (!Float.isNaN(d) && (d > m)) { m = data[j]; + mi = j; } } break; } } - return m; + return mi; } diff --git a/core/src/processing/data/IntDict.java b/core/src/processing/data/IntDict.java index e207a6fe1..971dc6e1e 100644 --- a/core/src/processing/data/IntDict.java +++ b/core/src/processing/data/IntDict.java @@ -355,6 +355,7 @@ public class IntDict { add(key, 1); } + /** * @webref intdict:method * @brief Add to a value @@ -368,6 +369,7 @@ public class IntDict { } } + /** * @webref intdict:method * @brief Subtract from a value @@ -376,6 +378,7 @@ public class IntDict { add(key, -amount); } + /** * @webref intdict:method * @brief Multiply a value @@ -387,6 +390,7 @@ public class IntDict { } } + /** * @webref intdict:method * @brief Divide a value @@ -399,6 +403,74 @@ public class IntDict { } + private void checkMinMax(String functionName) { + if (count == 0) { + String msg = + String.format("Cannot use %s() on an empty %s.", + functionName, getClass().getSimpleName()); + throw new RuntimeException(msg); + } + } + + + // return the index of the minimum value + public int minIndex() { + checkMinMax("minIndex"); + int index = 0; + int value = values[0]; + for (int i = 1; i < count; i++) { + if (values[i] < value) { + index = i; + value = values[i]; + } + } + return index; + } + + + // return the minimum value + public int minValue() { + checkMinMax("minValue"); + return values[minIndex()]; + } + + + // return the key for the minimum value + public String minKey() { + checkMinMax("minKey"); + return keys[minIndex()]; + } + + + // return the index of the max value + public int maxIndex() { + checkMinMax("maxIndex"); + int index = 0; + int value = values[0]; + for (int i = 1; i < count; i++) { + if (values[i] > value) { + index = i; + value = values[i]; + } + } + return index; + } + + + // return the maximum value + public int maxValue() { + checkMinMax("maxValue"); + return values[maxIndex()]; + } + + + // return the key for the maximum value + public String maxKey() { + checkMinMax("maxKey"); + return keys[maxIndex()]; + } + + public int index(String what) { Integer found = indices.get(what); return (found == null) ? -1 : found.intValue(); @@ -420,13 +492,18 @@ public class IntDict { * @webref intdict:method * @brief Remove a key/value pair */ - public void remove(String key) { - removeIndex(index(key)); + public int remove(String key) { + int index = index(key); + if (index != -1) { + removeIndex(index); + } + return index; } - public void removeIndex(int index) { + public String removeIndex(int index) { //System.out.println("index is " + which + " and " + keys[which]); + String key = keys[index]; indices.remove(keys[index]); for (int i = index; i < count-1; i++) { keys[i] = keys[i+1]; @@ -436,6 +513,7 @@ public class IntDict { count--; keys[count] = null; values[count] = 0; + return key; } diff --git a/core/src/processing/data/IntList.java b/core/src/processing/data/IntList.java index 80ba7840c..aa27fce56 100644 --- a/core/src/processing/data/IntList.java +++ b/core/src/processing/data/IntList.java @@ -137,41 +137,47 @@ public class IntList implements Iterable { * @webref floatlist:method * @brief Remove an element from the specified index */ - public void remove(int index) { + public int remove(int index) { + int entry = data[index]; // int[] outgoing = new int[count - 1]; // System.arraycopy(data, 0, outgoing, 0, index); // count--; // System.arraycopy(data, index + 1, outgoing, 0, count - index); // data = outgoing; + // For most cases, this actually appears to be faster + // than arraycopy() on an array copying into itself. for (int i = index; i < count-1; i++) { data[i] = data[i+1]; } count--; + return entry; } - /** Remove the first instance of a particular value */ - public boolean removeValue(int value) { + // Remove the first instance of a particular value, + // and return the index at which it was found. + public int removeValue(int value) { int index = index(value); if (index != -1) { remove(index); - return true; + return index; } - return false; + return -1; } - /** Remove all instances of a particular value */ - public boolean removeValues(int value) { + // Remove all instances of a particular value, + // and return the number of values found and removed + public int removeValues(int value) { int ii = 0; for (int i = 0; i < count; i++) { if (data[i] != value) { data[ii++] = data[i]; } } - boolean changed = count == ii; + int removed = count - ii; count = ii; - return changed; + return removed; } @@ -396,37 +402,77 @@ public class IntList implements Iterable { data[index] /= amount; } + + private void checkMinMax(String functionName) { + if (count == 0) { + String msg = + String.format("Cannot use %s() on an empty %s.", + functionName, getClass().getSimpleName()); + throw new RuntimeException(msg); + } + } + + /** * @webref floatlist:method * @brief Return the smallest value */ public int min() { - if (count == 0) { - throw new ArrayIndexOutOfBoundsException("Cannot use min() on IntList of length 0."); - } + checkMinMax("min"); int outgoing = data[0]; - for (int i = 1; i < data.length; i++) { + for (int i = 1; i < count; i++) { if (data[i] < outgoing) outgoing = data[i]; } return outgoing; } + + // returns the index of the minimum value. + // if there are ties, it returns the first one found. + public int minIndex() { + checkMinMax("minIndex"); + int value = data[0]; + int index = 0; + for (int i = 1; i < count; i++) { + if (data[i] < value) { + value = data[i]; + index = i; + } + } + return index; + } + + /** * @webref floatlist:method * @brief Return the largest value */ public int max() { - if (count == 0) { - throw new ArrayIndexOutOfBoundsException("Cannot use max() on IntList of length 0."); - } + checkMinMax("max"); int outgoing = data[0]; - for (int i = 1; i < data.length; i++) { + for (int i = 1; i < count; i++) { if (data[i] > outgoing) outgoing = data[i]; } return outgoing; } + // returns the index of the maximum value. + // if there are ties, it returns the first one found. + public int maxIndex() { + checkMinMax("maxIndex"); + int value = data[0]; + int index = 0; + for (int i = 1; i < count; i++) { + if (data[i] > value) { + value = data[i]; + index = i; + } + } + return index; + } + + /** * Sorts the array in place. * diff --git a/core/src/processing/data/StringDict.java b/core/src/processing/data/StringDict.java index 2813b7da8..bc3124835 100644 --- a/core/src/processing/data/StringDict.java +++ b/core/src/processing/data/StringDict.java @@ -282,14 +282,19 @@ public class StringDict { * @webref stringdict:method * @brief Remove a key/value pair */ - public void remove(String key) { - removeIndex(index(key)); + public int remove(String key) { + int index = index(key); + if (index != -1) { + removeIndex(index); + } + return index; } - public void removeIndex(int index) { + public String removeIndex(int index) { //System.out.println("index is " + which + " and " + keys[which]); - indices.remove(keys[index]); + String key = keys[index]; + indices.remove(key); for (int i = index; i < count-1; i++) { keys[i] = keys[i+1]; values[i] = values[i+1]; @@ -298,6 +303,7 @@ public class StringDict { count--; keys[count] = null; values[count] = null; + return key; } diff --git a/core/src/processing/data/StringList.java b/core/src/processing/data/StringList.java index e242a2e52..5873d53c2 100644 --- a/core/src/processing/data/StringList.java +++ b/core/src/processing/data/StringList.java @@ -133,7 +133,8 @@ public class StringList implements Iterable { * @webref stringlist:method * @brief Remove an element from the specified index */ - public void remove(int index) { + public String remove(int index) { + String entry = data[index]; // int[] outgoing = new int[count - 1]; // System.arraycopy(data, 0, outgoing, 0, index); // count--; @@ -143,31 +144,32 @@ public class StringList implements Iterable { data[i] = data[i+1]; } count--; + return entry; } - /** Remove the first instance of a particular value */ - public boolean removeValue(String value) { + // Remove the first instance of a particular value and return its index. + public int removeValue(String value) { if (value == null) { for (int i = 0; i < count; i++) { if (data[i] == null) { remove(i); - return true; + return i; } } } else { int index = index(value); if (index != -1) { remove(index); - return true; + return index; } } - return false; + return -1; } - /** Remove all instances of a particular value */ - public boolean removeValues(String value) { + // Remove all instances of a particular value and return the count removed. + public int removeValues(String value) { int ii = 0; if (value == null) { for (int i = 0; i < count; i++) { @@ -182,46 +184,48 @@ public class StringList implements Iterable { } } } - boolean changed = count == ii; + int removed = count - ii; count = ii; - return changed; + return removed; } - public boolean replaceValue(String value, String newValue) { + // replace the first value that matches, return the index that was replaced + public int replaceValue(String value, String newValue) { if (value == null) { for (int i = 0; i < count; i++) { if (data[i] == null) { data[i] = newValue; - return true; + return i; } } } else { for (int i = 0; i < count; i++) { if (value.equals(data[i])) { data[i] = newValue; - return true; + return i; } } } - return false; + return -1; } - public boolean replaceValues(String value, String newValue) { - boolean changed = false; + // replace all values that match, return the count of those replaced + public int replaceValues(String value, String newValue) { + int changed = 0; if (value == null) { for (int i = 0; i < count; i++) { if (data[i] == null) { data[i] = newValue; - changed = true; + changed++; } } } else { for (int i = 0; i < count; i++) { if (value.equals(data[i])) { data[i] = newValue; - changed = true; + changed++; } } }