diff --git a/.gitignore b/.gitignore
index 00fe968..76393c0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,9 @@
-/target/
.classpath
.project
*.settings
-.editorconfig
\ No newline at end of file
+.editorconfig
+.idea/
+*.iml
+build/
+.gradle/
+out/
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..6dd6cfd
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,27 @@
+plugins {
+ id 'java'
+}
+
+group = 'com.lewdev'
+version = '0.8'
+description = 'probability-lib'
+sourceCompatibility = '1.8'
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ compileOnly 'org.jetbrains:annotations:19.0.0'
+ testImplementation 'org.openjdk.jmh:jmh-generator-annprocess:1.23'
+ testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.1.0'
+ testImplementation 'org.hamcrest:hamcrest-core:2.2'
+}
+
+tasks.withType(JavaCompile) {
+ options.encoding = 'UTF-8'
+}
+
+test {
+ useJUnitPlatform()
+}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..62d4c05
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..9ea5a58
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Sat Jul 18 00:55:54 AWST 2020
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStorePath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
diff --git a/gradlew b/gradlew
new file mode 100644
index 0000000..fbd7c51
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..5093609
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,104 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/pom.xml b/pom.xml
index f1fe868..08f03ef 100644
--- a/pom.xml
+++ b/pom.xml
@@ -18,6 +18,15 @@
+
+ org.jetbrains
+ annotations
+ 19.0.0
+ compile
+
+
+
org.junit.jupiter
junit-jupiter-engine
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..cd2ca5b
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,5 @@
+/*
+ * This file was generated by the Gradle 'init' task.
+ */
+
+rootProject.name = 'probability-lib'
diff --git a/src/main/java/com/lewdev/probabilitylib/ProbabilityCollection.java b/src/main/java/com/lewdev/probabilitylib/ProbabilityCollection.java
index 98bd9b1..0faa8f9 100644
--- a/src/main/java/com/lewdev/probabilitylib/ProbabilityCollection.java
+++ b/src/main/java/com/lewdev/probabilitylib/ProbabilityCollection.java
@@ -1,32 +1,30 @@
/*
-* Copyright (c) 2020 Lewys Davies
-*
-* Permission is hereby granted, free of charge, to any person obtaining a copy
-* of this software and associated documentation files (the "Software"), to deal
-* in the Software without restriction, including without limitation the rights
-* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-* copies of the Software, and to permit persons to whom the Software is
-* furnished to do so, subject to the following conditions:
-*
-* The above copyright notice and this permission notice shall be included in all
-* copies or substantial portions of the Software.
-*
-* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-* SOFTWARE.
-*/
+ * Copyright (c) 2020 Lewys Davies
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
package com.lewdev.probabilitylib;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.NavigableSet;
-import java.util.Objects;
-import java.util.SplittableRandom;
-import java.util.TreeSet;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.*;
/**
* ProbabilityCollection for retrieving random elements based on probability.
@@ -43,214 +41,187 @@
* selected than those with smaller probability.
*
*
- *
- * @author Lewys Davies
- * @version 0.8
*
* @param Type of elements
+ * @author Lewys Davies
+ * @version 0.8
*/
public class ProbabilityCollection {
-
- private final NavigableSet> collection;
- private final SplittableRandom random = new SplittableRandom();
+ private final NavigableSet> collection =
+ new TreeSet<>(Comparator.comparingInt(ProbabilitySetElement::getIndex));
+ private final SplittableRandom random = new SplittableRandom();
+
+ private int totalProbability = 0;
+
+ /**
+ * @return Number of objects inside the collection
+ */
+ public int size() {
+ return this.collection.size();
+ }
+
+ /**
+ * @return True if collection contains no elements, else False
+ */
+ public boolean isEmpty() {
+ return this.collection.isEmpty();
+ }
+
+ /**
+ * @param object Object to test against
+ * @return True if collection contains the object, else False
+ * @throws IllegalArgumentException if object is null
+ */
+ public boolean contains(@NotNull E object) {
+ return this.collection.stream()
+ .anyMatch(entry -> entry.getObject().equals(object));
+ }
+
+ /**
+ * @return Iterator over this collection
+ */
+ @NotNull
+ public Iterator> iterator() {
+ return this.collection.iterator();
+ }
+
+ /**
+ * Add an object to this collection
+ *
+ * @param object Non-null object to add.
+ * @param probability share. Must be greater than 0.
+ * @throws IllegalArgumentException if probability <= 0
+ */
+ public void add(@NotNull E object, int probability) {
+ if (probability <= 0) {
+ throw new IllegalArgumentException("Probability must be greater than 0");
+ }
+
+ final ProbabilitySetElement entry = new ProbabilitySetElement<>(object, probability);
+ entry.setIndex(this.totalProbability + 1);
+
+ this.collection.add(entry);
+ this.totalProbability += probability;
+ }
+
+ /**
+ * Remove a object from this collection
+ *
+ * @param object Object to remove
+ * @return True if object was removed, else False.
+ */
+ public boolean remove(@NotNull E object) {
+ final Iterator> it = this.iterator();
+ boolean removed = false;
+
+ while (it.hasNext()) {
+ ProbabilitySetElement entry = it.next();
+
+ if (entry.getObject().equals(object)) {
+ this.totalProbability -= entry.getProbability();
+ it.remove();
+ removed = true;
+ }
+ }
+
+ this.updateIndexes();
+
+ return removed;
+ }
+
+ /**
+ * Remove all objects from this collection
+ */
+ public void clear() {
+ this.collection.clear();
+ this.totalProbability = 0;
+ }
+
+ /**
+ * Get a random object from this collection, based on probability.
+ *
+ * @return Random object
+ * @throws IllegalStateException if this collection is empty
+ */
+ @NotNull
+ public E get() {
+ if (this.isEmpty()) {
+ throw new IllegalStateException("Cannot get an object out of a empty collection");
+ }
+
+ final ProbabilitySetElement toFind = new ProbabilitySetElement<>(null, 0);
+ toFind.setIndex(this.random.nextInt(1, this.totalProbability + 1));
+
+ return Objects.requireNonNull(Objects.requireNonNull(this.collection.floor(toFind)).getObject());
+ }
+
+ /**
+ * @return Sum of all element's probability
+ */
+ public final int getTotalProbability() {
+ return this.totalProbability;
+ }
+
+ /*
+ * Calculate the size of all element's "block" of space:
+ * i.e 1-5, 6-10, 11-14, 15, 16
+ *
+ * We then only need to store the start index of each element,
+ * as we make use of the TreeSet#floor
+ */
+ private void updateIndexes() {
+ int previousIndex = 0;
+
+ for (final ProbabilitySetElement entry : this.collection) {
+ previousIndex = entry.setIndex(previousIndex + 1) + (entry.getProbability() - 1);
+ }
+ }
- private int totalProbability;
-
- /**
- * Construct a new Probability Collection
- */
- public ProbabilityCollection() {
- this.collection = new TreeSet<>(Comparator.comparingInt(ProbabilitySetElement::getIndex));
- this.totalProbability = 0;
- }
+ /**
+ * Used internally to store information about a object's
+ * state in a collection. Specifically, the probability
+ * and index within the collection.
+ *
+ * Indexes refer to the start position of this element's "block" of space.
+ * The space between element "block"s represents their probability of being selected
+ *
+ * @param Type of element
+ * @author Lewys Davies
+ */
+ private static final class ProbabilitySetElement {
+ private final T object;
+ private final int probability;
+ private int index;
- /**
- * @return Number of objects inside the collection
- */
- public int size() {
- return this.collection.size();
- }
-
- /**
- * @return True if collection contains no elements, else False
- */
- public boolean isEmpty() {
- return this.collection.isEmpty();
- }
-
- /**
- * @param object
- * @return True if collection contains the object, else False
- * @throws IllegalArgumentException if object is null
- */
- public boolean contains(E object) {
- if(object == null) {
- throw new IllegalArgumentException("Cannot check if null object is contained in this collection");
- }
-
- return this.collection.stream()
- .anyMatch(entry -> entry.getObject().equals(object));
- }
+ protected ProbabilitySetElement(T object, int probability) {
+ this.object = object;
+ this.probability = probability;
+ }
- /**
- * @return Iterator over this collection
- */
- public Iterator> iterator() {
- return this.collection.iterator();
- }
-
- /**
- * Add an object to this collection
- *
- * @param object. Not null.
- * @param probability share. Must be greater than 0.
- *
- * @throws IllegalArgumentException if object is null
- * @throws IllegalArgumentException if probability <= 0
- */
- public void add(E object, int probability) {
- if(object == null) {
- throw new IllegalArgumentException("Cannot add null object");
- }
-
- if(probability <= 0) {
- throw new IllegalArgumentException("Probability must be greater than 0");
- }
-
- ProbabilitySetElement entry = new ProbabilitySetElement(object, probability);
- entry.setIndex(this.totalProbability + 1);
-
- this.collection.add(entry);
- this.totalProbability += probability;
- }
+ /**
+ * @return The actual object
+ */
+ @Nullable
+ public T getObject() {
+ return this.object;
+ }
- /**
- * Remove a object from this collection
- *
- * @param object
- * @return True if object was removed, else False.
- *
- * @throws IllegalArgumentException if object is null
- */
- public boolean remove(E object) {
- if(object == null) {
- throw new IllegalArgumentException("Cannot remove null object");
- }
-
- Iterator> it = this.iterator();
- boolean removed = false;
-
- while(it.hasNext()) {
- ProbabilitySetElement entry = it.next();
- if(entry.getObject().equals(object)) {
- this.totalProbability -= entry.getProbability();
- it.remove();
- removed = true;
- }
- }
-
- this.updateIndexes();
-
- return removed;
- }
-
- /**
- * Remove all objects from this collection
- */
- public void clear() {
- this.collection.clear();
- this.totalProbability = 0;
- }
-
- /**
- * Get a random object from this collection, based on probability.
- *
- * @return Random object
- *
- * @throws IllegalStateException if this collection is empty
- */
- public E get() {
- if(this.isEmpty()) {
- throw new IllegalStateException("Cannot get an object out of a empty collection");
- }
-
- ProbabilitySetElement toFind = new ProbabilitySetElement<>(null, 0);
- toFind.setIndex(this.random.nextInt(1, this.totalProbability + 1));
-
- return Objects.requireNonNull(this.collection.floor(toFind).getObject());
- }
-
- /**
- * @return Sum of all element's probability
- */
- public final int getTotalProbability() {
- return this.totalProbability;
- }
-
- /*
- * Calculate the size of all element's "block" of space:
- * i.e 1-5, 6-10, 11-14, 15, 16
- *
- * We then only need to store the start index of each element,
- * as we make use of the TreeSet#floor
- */
- private final void updateIndexes() {
- int previousIndex = 0;
-
- for(ProbabilitySetElement entry : this.collection) {
- previousIndex = entry.setIndex(previousIndex + 1) + (entry.getProbability() - 1);
- }
- }
-
- /**
- * Used internally to store information about a object's
- * state in a collection. Specifically, the probability
- * and index within the collection.
- *
- * Indexes refer to the start position of this element's "block" of space.
- * The space between element "block"s represents their probability of being selected
- *
- * @author Lewys Davies
- *
- * @param Type of element
- */
- final static class ProbabilitySetElement {
- private final T object;
- private final int probability;
- private int index;
-
- /**
- * @param object
- * @param probability
- */
- protected ProbabilitySetElement(T object, int probability) {
- this.object = object;
- this.probability = probability;
- }
+ /**
+ * @return Probability share in this collection
+ */
+ public int getProbability() {
+ return this.probability;
+ }
- /**
- * @return The actual object
- */
- public final T getObject() {
- return this.object;
- }
+ // Used internally, see this class's documentation
+ private int getIndex() {
+ return this.index;
+ }
- /**
- * @return Probability share in this collection
- */
- public final int getProbability() {
- return this.probability;
- }
-
- // Used internally, see this class's documentation
- private final int getIndex() {
- return this.index;
- }
-
- // Used Internally, see this class's documentation
- private final int setIndex(int index) {
- this.index = index;
- return this.index;
- }
- }
+ // Used Internally, see this class's documentation
+ private int setIndex(int index) {
+ this.index = index;
+ return this.index;
+ }
+ }
}
diff --git a/src/test/java/com/lewdev/probabilitylib/ProbabilityCollectionTest.java b/src/test/java/com/lewdev/probabilitylib/ProbabilityCollectionTest.java
index 5bd0aae..277aeb4 100644
--- a/src/test/java/com/lewdev/probabilitylib/ProbabilityCollectionTest.java
+++ b/src/test/java/com/lewdev/probabilitylib/ProbabilityCollectionTest.java
@@ -1,10 +1,10 @@
package com.lewdev.probabilitylib;
-import static org.junit.jupiter.api.Assertions.*;
-
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.*;
+
/**
* @author Lewys Davies
*/
@@ -250,48 +250,29 @@ public void test_Errors() {
assertEquals(0, collection.size());
assertTrue(collection.isEmpty());
assertEquals(0, collection.getTotalProbability());
-
+
// Cannot get from empty collection
- assertThrows(IllegalStateException.class, () -> {
- collection.get();
- });
+ assertThrows(IllegalStateException.class, collection::get);
assertEquals(0, collection.size());
assertTrue(collection.isEmpty());
assertEquals(0, collection.getTotalProbability());
- // Cannot add null object
- assertThrows(IllegalArgumentException.class, () -> {
- collection.add(null, 1);
- });
-
assertEquals(0, collection.size());
assertTrue(collection.isEmpty());
assertEquals(0, collection.getTotalProbability());
// Cannot add prob 0
- assertThrows(IllegalArgumentException.class, () -> {
- collection.add("A", 0);
- });
+ assertThrows(IllegalArgumentException.class, () -> collection.add("A", 0));
assertEquals(0, collection.size());
assertTrue(collection.isEmpty());
assertEquals(0, collection.getTotalProbability());
- // Cannot remove null
- assertThrows(IllegalArgumentException.class, () -> {
- collection.remove(null);
- });
-
assertEquals(0, collection.size());
assertTrue(collection.isEmpty());
assertEquals(0, collection.getTotalProbability());
- // Cannot contains null
- assertThrows(IllegalArgumentException.class, () -> {
- collection.contains(null);
- });
-
assertEquals(0, collection.size());
assertTrue(collection.isEmpty());
assertEquals(0, collection.getTotalProbability());