From 21aa2e2221af553e19a568a9e1c43fa7dfc27a29 Mon Sep 17 00:00:00 2001 From: zihluwang Date: Thu, 22 Aug 2024 21:38:06 +0800 Subject: [PATCH 1/7] style: reduce redundant codes --- .../com/onixbyte/devkit/utils/BranchUtil.java | 44 +++++++------------ 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/devkit-utils/src/main/java/com/onixbyte/devkit/utils/BranchUtil.java b/devkit-utils/src/main/java/com/onixbyte/devkit/utils/BranchUtil.java index c6ad92e..eb67495 100644 --- a/devkit-utils/src/main/java/com/onixbyte/devkit/utils/BranchUtil.java +++ b/devkit-utils/src/main/java/com/onixbyte/devkit/utils/BranchUtil.java @@ -89,62 +89,50 @@ private BranchUtil(boolean result) { * Creates a {@code BranchUtil} instance to evaluate a logical OR operation on the provided * boolean expressions. * - * @param booleans the boolean expressions to be evaluated - * @param the type of the result to be handled by the methods + * @param values the boolean expressions to be evaluated + * @param the type of the result to be handled by the methods * @return a {@code BranchUtil} instance representing the result of the logical OR operation */ - public static BranchUtil or(Boolean... booleans) { - var result = Arrays.stream(booleans) - .filter(Objects::nonNull) - .anyMatch(Boolean::booleanValue); - return new BranchUtil<>(result); + public static BranchUtil or(Boolean... values) { + return new BranchUtil<>(BoolUtil.or(values)); } /** * Creates a {@code BranchUtil} instance to evaluate a logical AND operation on the provided * boolean expressions. * - * @param booleans the boolean expressions to be evaluated - * @param the type of the result to be handled by the methods + * @param values the boolean expressions to be evaluated + * @param the type of the result to be handled by the methods * @return a {@code BranchUtil} instance representing the result of the logical AND operation */ - public static BranchUtil and(Boolean... booleans) { - var result = Arrays.stream(booleans) - .filter(Objects::nonNull) - .allMatch(Boolean::booleanValue); - return new BranchUtil<>(result); + public static BranchUtil and(Boolean... values) { + return new BranchUtil<>(BoolUtil.and(values)); } /** * Creates a {@code BranchUtil} instance to evaluate a logical OR operation on the provided * boolean suppliers. * - * @param booleanSuppliers the boolean suppliers to be evaluated - * @param the type of the result to be handled by the methods + * @param valueSuppliers the boolean suppliers to be evaluated + * @param the type of the result to be handled by the methods * @return a {@code BranchUtil} instance representing the result of the * logical OR operation */ - public static BranchUtil or(BooleanSupplier... booleanSuppliers) { - var result = Arrays.stream(booleanSuppliers) - .filter(Objects::nonNull) - .anyMatch(BooleanSupplier::getAsBoolean); - return new BranchUtil<>(result); + public static BranchUtil or(BooleanSupplier... valueSuppliers) { + return new BranchUtil<>(BoolUtil.or(valueSuppliers)); } /** * Creates a {@code BranchUtil} instance to evaluate a logical AND operation on the provided * boolean suppliers. * - * @param booleanSuppliers the boolean suppliers to be evaluated - * @param the type of the result to be handled by the methods + * @param valueSuppliers the boolean suppliers to be evaluated + * @param the type of the result to be handled by the methods * @return a {@code BranchUtil} instance representing the result of the * logical AND operation */ - public static BranchUtil and(BooleanSupplier... booleanSuppliers) { - var result = Arrays.stream(booleanSuppliers) - .filter(Objects::nonNull) - .allMatch(BooleanSupplier::getAsBoolean); - return new BranchUtil<>(result); + public static BranchUtil and(BooleanSupplier... valueSuppliers) { + return new BranchUtil<>(BoolUtil.and(valueSuppliers)); } /** From 846c25a09881fca9d7f45070188ece451c8c4114 Mon Sep 17 00:00:00 2001 From: zihluwang Date: Thu, 22 Aug 2024 21:43:59 +0800 Subject: [PATCH 2/7] style: removed unused imports --- .../src/main/java/com/onixbyte/devkit/utils/BranchUtil.java | 1 - 1 file changed, 1 deletion(-) diff --git a/devkit-utils/src/main/java/com/onixbyte/devkit/utils/BranchUtil.java b/devkit-utils/src/main/java/com/onixbyte/devkit/utils/BranchUtil.java index eb67495..0d339d6 100644 --- a/devkit-utils/src/main/java/com/onixbyte/devkit/utils/BranchUtil.java +++ b/devkit-utils/src/main/java/com/onixbyte/devkit/utils/BranchUtil.java @@ -17,7 +17,6 @@ package com.onixbyte.devkit.utils; -import java.util.Arrays; import java.util.Objects; import java.util.function.BooleanSupplier; import java.util.function.Supplier; From 2ee29059b53bcf86b7875c65518b92253c006cde Mon Sep 17 00:00:00 2001 From: zihluwang Date: Sat, 14 Sep 2024 02:02:47 +0800 Subject: [PATCH 3/7] feat: added mathematic calculators --- num4j/build.gradle.kts | 19 ++++++ .../com/onixbyte/nums}/ChainedCalcUtil.java | 4 +- .../onixbyte/nums/PercentileCalculator.java | 62 ++++++++++++++++++ .../onixbyte/nums/model/QuartileBounds.java | 63 +++++++++++++++++++ settings.gradle.kts | 1 + 5 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 num4j/build.gradle.kts rename {devkit-utils/src/main/java/com/onixbyte/devkit/utils => num4j/src/main/java/com/onixbyte/nums}/ChainedCalcUtil.java (99%) create mode 100644 num4j/src/main/java/com/onixbyte/nums/PercentileCalculator.java create mode 100644 num4j/src/main/java/com/onixbyte/nums/model/QuartileBounds.java diff --git a/num4j/build.gradle.kts b/num4j/build.gradle.kts new file mode 100644 index 0000000..d95c6ac --- /dev/null +++ b/num4j/build.gradle.kts @@ -0,0 +1,19 @@ +plugins { + id("java") +} + +group = "com.onixbyte" +version = "unspecified" + +repositories { + mavenCentral() +} + +dependencies { + testImplementation(platform("org.junit:junit-bom:5.10.0")) + testImplementation("org.junit.jupiter:junit-jupiter") +} + +tasks.test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/devkit-utils/src/main/java/com/onixbyte/devkit/utils/ChainedCalcUtil.java b/num4j/src/main/java/com/onixbyte/nums/ChainedCalcUtil.java similarity index 99% rename from devkit-utils/src/main/java/com/onixbyte/devkit/utils/ChainedCalcUtil.java rename to num4j/src/main/java/com/onixbyte/nums/ChainedCalcUtil.java index 11bcc47..27242c9 100644 --- a/devkit-utils/src/main/java/com/onixbyte/devkit/utils/ChainedCalcUtil.java +++ b/num4j/src/main/java/com/onixbyte/nums/ChainedCalcUtil.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package com.onixbyte.devkit.utils; +package com.onixbyte.nums; import lombok.Getter; @@ -87,7 +87,7 @@ * * @author sunzsh * @version 1.1.0 - * @see java.math.BigDecimal + * @see BigDecimal * @since 1.0.0 */ @Getter diff --git a/num4j/src/main/java/com/onixbyte/nums/PercentileCalculator.java b/num4j/src/main/java/com/onixbyte/nums/PercentileCalculator.java new file mode 100644 index 0000000..692eaf0 --- /dev/null +++ b/num4j/src/main/java/com/onixbyte/nums/PercentileCalculator.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2024 OnixByte. + * + * 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 + * + * http://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. + */ +package com.onixbyte.nums; + +import com.onixbyte.nums.model.QuartileBounds; + +import java.util.List; + +/** + * Percentile calculator. + * + * @author zihluwang + * @version 1.7.0 + * @since 1.7.0 + */ +public final class PercentileCalculator { + + public static Double calculatePercentile(List values, Double percentile) { + var sorted = values.stream().sorted().toList(); + if (sorted.isEmpty()) { + throw new IllegalArgumentException("Unable to sort an empty list."); + } + + var rank = percentile / 100. * (sorted.size() - 1); + var lowerIndex = ((int) Math.floor(rank)); + var upperIndex = ((int) Math.ceil(rank)); + var weight = rank - lowerIndex; + + return sorted.get(lowerIndex) * (1 - weight) + sorted.get(upperIndex) * weight; + } + + public static QuartileBounds calculatePercentileBounds(List data) { + var sorted = data.stream().sorted().toList(); + var Q1 = calculatePercentile(sorted, 25.); + var Q3 = calculatePercentile(sorted, 75.); + + var IQR = Q3 - Q1; + + var lowerBound = Q1 - 1.5 * IQR; + var upperBound = Q3 + 1.5 * IQR; + + return QuartileBounds.builder() + .upperBound(upperBound) + .lowerBound(lowerBound) + .build(); + } + +} diff --git a/num4j/src/main/java/com/onixbyte/nums/model/QuartileBounds.java b/num4j/src/main/java/com/onixbyte/nums/model/QuartileBounds.java new file mode 100644 index 0000000..45c6d24 --- /dev/null +++ b/num4j/src/main/java/com/onixbyte/nums/model/QuartileBounds.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2024-2024 OnixByte. + * + * 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 + * + * http://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. + */ + +package com.onixbyte.nums.model; + +/** + * QuartileBound. + * + * @param upperBound + * @param lowerBound + * @author zihluwang + */ +public record QuartileBounds( + Double upperBound, + Double lowerBound +) { + + /** + * Get a builder for {@link QuartileBounds}. + * + * @return a builder + */ + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private Double upperBound; + private Double lowerBound; + + private Builder() { + } + + public Builder upperBound(Double upperBound) { + this.upperBound = upperBound; + return this; + } + + public Builder lowerBound(Double lowerBound) { + this.lowerBound = lowerBound; + return this; + } + + public QuartileBounds build() { + return new QuartileBounds(upperBound, lowerBound); + } + } + +} diff --git a/settings.gradle.kts b/settings.gradle.kts index d39293c..b840c05 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -28,3 +28,4 @@ include( "simple-jwt-spring-boot-starter", "property-guard-spring-boot-starter" ) +include("num4j") From 8db8669c898cf7f8238753923b2b77de351feb0b Mon Sep 17 00:00:00 2001 From: zihluwang Date: Tue, 22 Oct 2024 12:47:58 +0800 Subject: [PATCH 4/7] chore: updated dependencies --- gradle.properties | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/gradle.properties b/gradle.properties index ecf33a6..435e1d8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,18 +15,17 @@ # limitations under the License. # -jacksonVersion=2.17.2 +jacksonVersion=2.18.0 javaJwtVersion=4.4.0 -jjwtVersion=0.12.6 -junitVersion=5.10.2 -logbackVersion=1.5.4 -lombokVersion=1.18.30 -slf4jVersion=2.0.9 -springVersion=6.1.3 -springBootVersion=3.2.3 +junitVersion=5.11.2 +logbackVersion=1.5.10 +lombokVersion=1.18.34 +slf4jVersion=2.0.16 +springVersion=6.1.13 +springBootVersion=3.3.4 buildGroupId=com.onixbyte -buildVersion=1.6.4 +buildVersion=1.6.5 projectUrl=https://onixbyte.com/JDevKit projectGithubUrl=https://github.com/OnixByte/JDevKit licenseName=The Apache License, Version 2.0 From fa10b9538d337500a724c0bcf4147ae1838ecf0c Mon Sep 17 00:00:00 2001 From: zihluwang Date: Tue, 22 Oct 2024 13:34:48 +0800 Subject: [PATCH 5/7] docs: updated docs --- .../onixbyte/nums/PercentileCalculator.java | 54 +++++++++++++++++-- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/num4j/src/main/java/com/onixbyte/nums/PercentileCalculator.java b/num4j/src/main/java/com/onixbyte/nums/PercentileCalculator.java index 692eaf0..0992f24 100644 --- a/num4j/src/main/java/com/onixbyte/nums/PercentileCalculator.java +++ b/num4j/src/main/java/com/onixbyte/nums/PercentileCalculator.java @@ -21,14 +21,45 @@ import java.util.List; /** - * Percentile calculator. + * A utility class that provides methods for calculating percentiles and interquartile range (IQR) bounds + * for a dataset. + *

+ * This class contains static methods to: + *

    + *
  • Calculate a specified percentile from a list of double values using linear interpolation.
  • + *
  • Calculate interquartile bounds (Q1, Q3) and the corresponding lower and upper bounds, + * which can be used to identify outliers in the dataset.
  • + *
+ *

+ * This class is final, meaning it cannot be subclassed, and it only contains static methods, + * so instances of the class cannot be created. + *

+ *

Example usage:

+ *
+ * {@code
+ * List data = Arrays.asList(1.0, 2.0, 3.0, 4.0, 5.0);
+ * Double percentileValue = PercentileCalculator.calculatePercentile(data, 50.0);  // Calculates median
+ * QuartileBounds bounds = PercentileCalculator.calculatePercentileBounds(data);   // Calculates IQR bounds
+ * }
+ * 
* * @author zihluwang - * @version 1.7.0 - * @since 1.7.0 + * @version 1.6.5 + * @since 1.6.5 */ public final class PercentileCalculator { + /** + * Calculates the specified percentile from a list of values. + *

+ * This method takes a list of double values and calculates the given percentile using linear interpolation between + * the two closest ranks. The list is first sorted in ascending order, and the specified percentile is + * then calculated. + * + * @param values a list of {@code Double} values from which the percentile is calculated. + * @param percentile a {@code Double} representing the percentile to be calculated (e.g., 50.0 for the median) + * @return a {@code Double} value representing the calculated percentile + */ public static Double calculatePercentile(List values, Double percentile) { var sorted = values.stream().sorted().toList(); if (sorted.isEmpty()) { @@ -36,13 +67,26 @@ public static Double calculatePercentile(List values, Double percentile) } var rank = percentile / 100. * (sorted.size() - 1); - var lowerIndex = ((int) Math.floor(rank)); - var upperIndex = ((int) Math.ceil(rank)); + var lowerIndex = (int) Math.floor(rank); + var upperIndex = (int) Math.ceil(rank); var weight = rank - lowerIndex; return sorted.get(lowerIndex) * (1 - weight) + sorted.get(upperIndex) * weight; } + /** + * Calculates the interquartile range (IQR) and the corresponding lower and upper bounds + * based on the first (Q1) and third (Q3) quartiles of a dataset. + *

+ * This method takes a list of double values, calculates the first quartile (Q1), + * the third quartile (Q3), and the interquartile range (IQR). Using the IQR, it computes + * the lower and upper bounds, which can be used to detect outliers in the dataset. + * The lower bound is defined as {@code Q1 - 1.5 * IQR}, and the upper bound is defined as + * {@code Q3 + 1.5 * IQR}. + * + * @param data a list of {@code Double} values for which the quartile bounds will be calculated + * @return a {@code QuartileBounds} object containing the calculated lower and upper bounds + */ public static QuartileBounds calculatePercentileBounds(List data) { var sorted = data.stream().sorted().toList(); var Q1 = calculatePercentile(sorted, 25.); From 6776d6e88bc0951dd3b36c0539849bb074d63ae3 Mon Sep 17 00:00:00 2001 From: zihluwang Date: Tue, 22 Oct 2024 13:45:03 +0800 Subject: [PATCH 6/7] docs: updated docs for record class QuartileBounds --- .../onixbyte/nums/model/QuartileBounds.java | 74 +++++++++++++++++-- 1 file changed, 69 insertions(+), 5 deletions(-) diff --git a/num4j/src/main/java/com/onixbyte/nums/model/QuartileBounds.java b/num4j/src/main/java/com/onixbyte/nums/model/QuartileBounds.java index 45c6d24..3936e61 100644 --- a/num4j/src/main/java/com/onixbyte/nums/model/QuartileBounds.java +++ b/num4j/src/main/java/com/onixbyte/nums/model/QuartileBounds.java @@ -18,11 +18,32 @@ package com.onixbyte.nums.model; /** - * QuartileBound. + * A record representing the quartile bounds of a dataset. + *

+ * This class encapsulates the lower and upper bounds of a dataset, which are typically used for detecting outliers in + * the data. The bounds are calculated based on the interquartile range (IQR) of the dataset. Values below the lower + * bound or above the upper bound may be considered outliers. + *

+ * Quartile bounds consist of: + *

    + *
  • {@code lowerBound} - The lower bound of the dataset, typically {@code Q1 - 1.5 * IQR}.
  • + *
  • {@code upperBound} - The upper bound of the dataset, typically {@code Q3 + 1.5 * IQR}.
  • + *
+ *

+ *

+ * Example usage: + *

+ * QuartileBounds bounds = QuartileBounds.builder()
+ *     .lowerBound(1.5)
+ *     .upperBound(7.5)
+ *     .build();
+ * 
* - * @param upperBound - * @param lowerBound + * @param upperBound the upper bound of the dataset + * @param lowerBound the lower bound of the dataset * @author zihluwang + * @version 1.6.5 + * @since 1.6.5 */ public record QuartileBounds( Double upperBound, @@ -30,31 +51,74 @@ public record QuartileBounds( ) { /** - * Get a builder for {@link QuartileBounds}. + * Creates a new {@link Builder} instance for building a {@code QuartileBounds} object. + *

+ * The {@link Builder} pattern is used to construct the {@code QuartileBounds} object with optional values for the + * upper and lower bounds. + *

* - * @return a builder + * @return a new instance of the {@link Builder} class */ public static Builder builder() { return new Builder(); } + /** + * A builder class for constructing instances of the {@code QuartileBounds} record. + *

+ * The {@link Builder} pattern allows for the step-by-step construction of a {@code QuartileBounds} object, + * providing a flexible way to set values for the lower and upper bounds. Once the builder has the required values, + * the {@link #build()} method creates and returns a new {@code QuartileBounds} object. + *

+ *

+ * Example usage: + *

+     * {@code
+     * QuartileBounds bounds = QuartileBounds.builder()
+     *     .lowerBound(1.5)
+     *     .upperBound(7.5)
+     *     .build();
+     * }
+     * 
+ */ public static class Builder { private Double upperBound; private Double lowerBound; + /** + * Private constructor for {@code Builder}, ensuring it can only be instantiated through the + * {@link QuartileBounds#builder()} method. + */ private Builder() { } + /** + * Sets the upper bound for the {@code QuartileBounds}. + * + * @param upperBound the upper bound of the dataset + * @return the current {@code Builder} instance, for method chaining + */ public Builder upperBound(Double upperBound) { this.upperBound = upperBound; return this; } + /** + * Sets the lower bound for the {@code QuartileBounds}. + * + * @param lowerBound the lower bound of the dataset + * @return the current {@code Builder} instance, for method chaining + */ public Builder lowerBound(Double lowerBound) { this.lowerBound = lowerBound; return this; } + /** + * Builds and returns a new {@code QuartileBounds} instance with the specified upper and lower bounds. + * + * @return a new {@code QuartileBounds} object containing the specified bounds + */ public QuartileBounds build() { return new QuartileBounds(upperBound, lowerBound); } From cc99b8919a3bb9b9985c14ef4c889a02abf7945b Mon Sep 17 00:00:00 2001 From: zihluwang Date: Tue, 22 Oct 2024 17:29:20 +0800 Subject: [PATCH 7/7] ci: changed trigger to release published and changed some settings --- .github/workflows/github-packages-publish.yml | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/.github/workflows/github-packages-publish.yml b/.github/workflows/github-packages-publish.yml index e93a4af..6601e5d 100644 --- a/.github/workflows/github-packages-publish.yml +++ b/.github/workflows/github-packages-publish.yml @@ -8,9 +8,9 @@ name: Publish Packages to GitHub Packages with Gradle on: - push: - branches: - - main + release: + types: + - published jobs: build: @@ -51,19 +51,17 @@ jobs: - name: Set up JDK 17 uses: actions/setup-java@v4 with: - java-version: '17' - distribution: 'corretto' - server-id: github # Value of the distributionManagement/repository/id field of the pom.xml - settings-path: ${{ github.workspace }} # location for the settings.xml file + java-version: "17" + distribution: "corretto" - name: Setup Gradle - uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 + uses: gradle/actions/setup-gradle@v4 - name: Grant Execution Authority to Gradlew run: chmod +x ./gradlew - name: Build with Gradle - run: ./gradlew build + run: ./gradlew build -PartefactVersion=${{ github.event.release.tag_name }} # Overwrite artefactVersion - name: Publish to Maven Central run: ./gradlew publish