From 183977b1be8cce166222775b74b84a713fcca13c Mon Sep 17 00:00:00 2001 From: "milo.simpson" Date: Sat, 1 Oct 2016 19:33:00 -0500 Subject: [PATCH] New Math Stock functions - intSum, doubleSum, longSum, divide and divideAndRound --- .../java/com/bazaarvoice/jolt/Modifier.java | 4 ++- .../jolt/modifier/function/Math.java | 33 +++++++++++++++++-- .../jolt/modifier/function/MathTest.java | 14 ++++---- .../json/modifier/functions/mathTests.json | 22 +++++++------ 4 files changed, 52 insertions(+), 21 deletions(-) diff --git a/jolt-core/src/main/java/com/bazaarvoice/jolt/Modifier.java b/jolt-core/src/main/java/com/bazaarvoice/jolt/Modifier.java index d57b8469..7cb0e08f 100644 --- a/jolt-core/src/main/java/com/bazaarvoice/jolt/Modifier.java +++ b/jolt-core/src/main/java/com/bazaarvoice/jolt/Modifier.java @@ -53,7 +53,9 @@ public abstract class Modifier implements SpecDriven, ContextualTransform { STOCK_FUNCTIONS.put( "intSum", new Math.intSum() ); STOCK_FUNCTIONS.put( "doubleSum", new Math.doubleSum() ); STOCK_FUNCTIONS.put( "longSum", new Math.longSum() ); - STOCK_FUNCTIONS.put( "div", new Math.div() ); + STOCK_FUNCTIONS.put( "divide", new Math.divide() ); + STOCK_FUNCTIONS.put( "divideAndRound", new Math.divideAndRound() ); + STOCK_FUNCTIONS.put( "toInteger", new Objects.toInteger() ); STOCK_FUNCTIONS.put( "toDouble", new Objects.toDouble() ); diff --git a/jolt-core/src/main/java/com/bazaarvoice/jolt/modifier/function/Math.java b/jolt-core/src/main/java/com/bazaarvoice/jolt/modifier/function/Math.java index 3d4a4619..89067104 100644 --- a/jolt-core/src/main/java/com/bazaarvoice/jolt/modifier/function/Math.java +++ b/jolt-core/src/main/java/com/bazaarvoice/jolt/modifier/function/Math.java @@ -18,6 +18,9 @@ import com.bazaarvoice.jolt.common.Optional; +import java.math.BigDecimal; +import java.math.MathContext; +import java.math.RoundingMode; import java.util.List; @SuppressWarnings( "deprecated" ) @@ -237,7 +240,7 @@ public static Optional longSum(List args) { return Optional.of(sum); } - public static Optional div(List argList) { + public static Optional divide(List argList) { if(argList.size() < 2) { return Optional.empty(); @@ -261,6 +264,19 @@ public static Optional div(List argList) { return Optional.empty(); } + public static Optional divideAndRound(List argList, int digitsAfterDecimalPoint ) { + + Optional divideResult = divide(argList); + + if(divideResult.isPresent()){ + Double divResult = divideResult.get(); + BigDecimal bigDecimal = new BigDecimal(divResult).setScale(digitsAfterDecimalPoint, RoundingMode.HALF_UP); + return Optional.of(bigDecimal.doubleValue()); + } + + return Optional.empty(); + } + @SuppressWarnings( "unchecked" ) public static final class max extends Function.BaseFunction { @Override @@ -307,14 +323,25 @@ protected Optional applySingle( final Object arg ) { } @SuppressWarnings( "unchecked" ) - public static final class div extends Function.ListFunction { + public static final class divide extends Function.ListFunction { @Override protected Optional applyList(List argList) { - return (Optional)div(argList); + return (Optional)divide(argList); } } + + @SuppressWarnings( "unchecked" ) + public static final class divideAndRound extends Function.ArgDrivenListFunction { + + + @Override + protected Optional applyList(Integer digitsAfterDecimalPoint, List args) { + return (Optional)divideAndRound(args, digitsAfterDecimalPoint); + } + } + @SuppressWarnings( "unchecked" ) public static final class avg extends Function.ListFunction { @Override diff --git a/jolt-core/src/test/java/com/bazaarvoice/jolt/modifier/function/MathTest.java b/jolt-core/src/test/java/com/bazaarvoice/jolt/modifier/function/MathTest.java index 7bcc627e..0cf3d3ea 100644 --- a/jolt-core/src/test/java/com/bazaarvoice/jolt/modifier/function/MathTest.java +++ b/jolt-core/src/test/java/com/bazaarvoice/jolt/modifier/function/MathTest.java @@ -47,7 +47,8 @@ public Iterator getTestCases() { Function DOUBLE_SUM_OF = new Math.doubleSum(); Function LONG_SUM_OF = new Math.longSum(); - Function DIV_OF = new Math.div(); + Function DIV_OF = new Math.divide(); + Function DIV_AND_ROUND_OF = new Math.divideAndRound(); testCases.add( new Object[] { "max-empty-array", MAX_OF, new Object[] {}, Optional.empty() } ); testCases.add( new Object[] { "max-empty-list", MAX_OF, new ArrayList( ), Optional.empty() } ); @@ -134,7 +135,6 @@ public Iterator getTestCases() { testCases.add( new Object[] { "min-NaN-positive-infinity", MIN_OF, Arrays.asList( -1.0, Double.NaN, Double.NEGATIVE_INFINITY ), Optional.of( Double.NaN ) } ); - testCases.add( new Object[] { "abs-null", ABS_OF, null, Optional.empty() } ); testCases.add( new Object[] { "abs-invalid", ABS_OF, new Object(), Optional.empty() } ); testCases.add( new Object[] { "abs-empty-list", ABS_OF, new Object[] {}, Optional.empty() } ); @@ -155,7 +155,6 @@ public Iterator getTestCases() { testCases.add( new Object[] { "abs-NefInfinity", ABS_OF, Double.NEGATIVE_INFINITY, Optional.of(Double.POSITIVE_INFINITY) } ); - testCases.add( new Object[] { "toInt-null", TO_INTEGER, null, Optional.empty() } ); testCases.add( new Object[] { "toInt-invalid", TO_INTEGER, new Object(), Optional.empty() } ); testCases.add( new Object[] { "toInt-empty-array", TO_INTEGER, new Object[] {}, Optional.empty() } ); @@ -180,7 +179,6 @@ public Iterator getTestCases() { testCases.add( new Object[] { "toInt-single-negative-double-array", TO_INTEGER, Arrays.asList( -1.0, -2.0 ), Optional.of( Arrays.asList( -1, -2 ) ) } ); - testCases.add( new Object[] { "toDouble-null", TO_DOUBLE, null, Optional.empty() } ); testCases.add( new Object[] { "toDouble-invalid", TO_DOUBLE, new Object(), Optional.empty() } ); testCases.add( new Object[] { "toDouble-empty-array", TO_DOUBLE, new Object[] {}, Optional.empty() } ); @@ -205,7 +203,6 @@ public Iterator getTestCases() { testCases.add( new Object[] { "toDouble-single-negative-double-array", TO_DOUBLE, Arrays.asList( -1.0, -2.0 ), Optional.of( Arrays.asList( -1.0, -2.0 ) ) } ); - testCases.add( new Object[] { "toLong-null", TO_LONG, null, Optional.empty() } ); testCases.add( new Object[] { "toLong-invalid", TO_LONG, new Object(), Optional.empty() } ); testCases.add( new Object[] { "toLong-empty-array", TO_LONG, new Object[] {}, Optional.empty() } ); @@ -229,8 +226,6 @@ public Iterator getTestCases() { testCases.add( new Object[] { "toLong-single-positive-double-list", TO_LONG, new Object[] {1L, 2L}, Optional.of( Arrays.asList( 1L, 2L ) ) } ); testCases.add( new Object[] { "toLong-single-negative-double-array", TO_LONG, Arrays.asList( -1L, -2L ), Optional.of( Arrays.asList( -1L, -2L ) ) } ); - - testCases.add( new Object[] { "toInteger-combo-string-array", TO_INTEGER, Arrays.asList( "-1", 2, -3L, 4.0 ), Optional.of( Arrays.asList( -1, 2, -3, 4 ) ) } ); testCases.add( new Object[] { "toLong-combo-int-array", TO_LONG, Arrays.asList( "-1", 2, -3L, 4.0 ), Optional.of( Arrays.asList( -1L, 2L, -3L, 4L ) ) } ); testCases.add( new Object[] { "toDouble-combo-long-array", TO_DOUBLE, Arrays.asList( "-1", 2, -3L, 4.0 ), Optional.of( Arrays.asList( -1.0, 2.0, -3.0, 4.0 ) ) } ); @@ -259,6 +254,11 @@ public Iterator getTestCases() { // Dividing 0 by any number returns 0.0(double) testCases.add( new Object[] { "div-combo-valid-array", DIV_OF, Arrays.asList(0.0, 10, 2), Optional.of(0.0)}); + testCases.add( new Object[] { "divAndRound-single-precision-array", DIV_AND_ROUND_OF, Arrays.asList(1, 5.0, 2), Optional.of(2.5)}); + testCases.add( new Object[] { "divAndRound-double-precision-array", DIV_AND_ROUND_OF, Arrays.asList(2, 5.0, 2), Optional.of(2.50)}); + testCases.add( new Object[] { "divAndRound-trailing-precision-array", DIV_AND_ROUND_OF, Arrays.asList(3, 5.0, 2), Optional.of(2.500)}); + testCases.add( new Object[] { "divAndRound-no-precision-array", DIV_AND_ROUND_OF, Arrays.asList(0, 5.0, 2), Optional.of(3.0)}); // Round up as >= 0.5 + testCases.add( new Object[] { "divAndRound-no-precision-array", DIV_AND_ROUND_OF, Arrays.asList(0, 4.8, 2), Optional.of(2.0)}); // Round down as < 0.5 return testCases.iterator(); } diff --git a/jolt-core/src/test/resources/json/modifier/functions/mathTests.json b/jolt-core/src/test/resources/json/modifier/functions/mathTests.json index c06961bf..ebe13bc6 100644 --- a/jolt-core/src/test/resources/json/modifier/functions/mathTests.json +++ b/jolt-core/src/test/resources/json/modifier/functions/mathTests.json @@ -14,8 +14,8 @@ "test1": [5, 2.0], // Divide integer and double returns double "test2": [5, 0], // Divide by 0 returns empty hence noop "test3": [0, 5], // Divide 0 by any number returns 0 - "nr": 10, - "dr": 5 + "nr": 51, + "dr": 13 } }, @@ -46,11 +46,12 @@ "value": "=intSum" }, "data4": { - "test1": "=div", - "test2": "=div", - "test3": "=div", - "explicit": "=div(@(1,value))", - "div": "=div(@(1,nr),@(1,dr))" // Look up the numerator and denominator from the input + "test1": "=divide", + "test2": "=divide", + "test3": "=divide", + "explicit": "=divide(@(1,value))", + "div": "=divide(@(1,nr),@(1,dr))" , // Look up the numerator and denominator from the input + "roundedDiv": "=divideAndRound(4, @(1,nr),@(1,dr))" // Round the result to the 4 decimal points } }, @@ -88,11 +89,12 @@ "test1": 2.5, "test2": [5, 0], "test3": 0.0, - "div": 2.0, + "div": 3.923076923076923, + "roundedDiv":3.9231, "explicit": 2.5, "value": [5, 2], - "nr": 10, - "dr": 5 + "nr": 51, + "dr": 13 } } }