-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Add all_match, any_match and none_match functions for arrays #13734
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,6 +21,20 @@ The ``||`` operator is used to concatenate an array with an array or an element | |
| Array Functions | ||
| --------------- | ||
|
|
||
| .. function:: all_match(array(T), function(T,boolean)) -> boolean | ||
|
|
||
| Returns whether all elements of an array match the given predicate. Returns ``true`` if all the elements | ||
| match the predicate (a special case is when the array is empty); ``false`` if one or more elements don't | ||
| match; ``NULL`` if the predicate function returns ``NULL`` for one or more elements and ``true`` for all | ||
| other elements. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about empty array? Every predicate would return true? Is that worth documenting?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @rongrong : It's already discussed: |
||
|
|
||
| .. function:: any_match(array(T), function(T,boolean)) -> boolean | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same as above |
||
|
|
||
| Returns whether any elements of an array match the given predicate. Returns ``true`` if one or more | ||
| elements match the predicate; ``false`` if none of the elements matches (a special case is when the | ||
| array is empty); ``NULL`` if the predicate function returns ``NULL`` for one or more elements and ``false`` | ||
| for all other elements. | ||
|
|
||
| .. function:: array_distinct(x) -> array | ||
|
|
||
| Remove duplicate values from the array ``x``. | ||
|
|
@@ -139,6 +153,12 @@ Array Functions | |
| SELECT ngrams(ARRAY['foo', 'bar', 'baz', 'foo'], 5); -- [['foo', 'bar', 'baz', 'foo']] | ||
| SELECT ngrams(ARRAY[1, 2, 3, 4], 2); -- [[1, 2], [2, 3], [3, 4]] | ||
|
|
||
| .. function:: none_match(array(T), function(T,boolean)) -> boolean | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It doesn't seem that the functions are actually listed in alphabetical order so it probably makes more sense to keep these three functions together.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @rongrong : Looks to me the functions are listed in alphabetical order? Maybe some functions are not following the ordering strictly (although I didn't see it with skim 😄 ) and we should fix them?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe it's the array_intersect/union/except that's wrong then. Can you add a follow up PR to fix that? Thanks!
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. also add space here.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| Returns whether no elements of an array match the given predicate. Returns ``true`` if none of the elements | ||
| matches the predicate (a special case is when the array is empty); ``false`` if one or more elements match; | ||
| ``NULL`` if the predicate function returns ``NULL`` for one or more elements and ``false`` for all other elements. | ||
|
|
||
| .. function:: reduce(array(T), initialState S, inputFunction(S,T,S), outputFunction(S,R)) -> R | ||
|
|
||
| Returns a single value reduced from ``array``. ``inputFunction`` will | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,183 @@ | ||
| /* | ||
| * 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.facebook.presto.operator.scalar; | ||
|
|
||
| import com.facebook.presto.spi.block.Block; | ||
| import com.facebook.presto.spi.function.Description; | ||
| import com.facebook.presto.spi.function.ScalarFunction; | ||
| import com.facebook.presto.spi.function.SqlNullable; | ||
| import com.facebook.presto.spi.function.SqlType; | ||
| import com.facebook.presto.spi.function.TypeParameter; | ||
| import com.facebook.presto.spi.function.TypeParameterSpecialization; | ||
| import com.facebook.presto.spi.type.StandardTypes; | ||
| import com.facebook.presto.spi.type.Type; | ||
| import io.airlift.slice.Slice; | ||
|
|
||
| import static java.lang.Boolean.FALSE; | ||
|
|
||
| @Description("Returns true if all elements of the array match the given predicate") | ||
| @ScalarFunction(value = "all_match") | ||
| public final class ArrayAllMatchFunction | ||
| { | ||
| private ArrayAllMatchFunction() {} | ||
|
|
||
| @TypeParameter("T") | ||
| @TypeParameterSpecialization(name = "T", nativeContainerType = Block.class) | ||
| @SqlType(StandardTypes.BOOLEAN) | ||
| @SqlNullable | ||
| public static Boolean allMatchBlock( | ||
| @TypeParameter("T") Type elementType, | ||
| @SqlType("array(T)") Block arrayBlock, | ||
| @SqlType("function(T, boolean)") BlockToBooleanFunction function) | ||
| { | ||
| boolean hasNullResult = false; | ||
| for (int i = 0; i < arrayBlock.getPositionCount(); i++) { | ||
| Block element = null; | ||
| if (!arrayBlock.isNull(i)) { | ||
| element = (Block) elementType.getObject(arrayBlock, i); | ||
| } | ||
| Boolean match = function.apply(element); | ||
| if (FALSE.equals(match)) { | ||
| return false; | ||
| } | ||
| if (match == null) { | ||
| hasNullResult = true; | ||
| } | ||
| } | ||
| if (hasNullResult) { | ||
| return null; | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
| @TypeParameter("T") | ||
| @TypeParameterSpecialization(name = "T", nativeContainerType = Slice.class) | ||
| @SqlType(StandardTypes.BOOLEAN) | ||
| @SqlNullable | ||
| public static Boolean allMatchSlice( | ||
| @TypeParameter("T") Type elementType, | ||
| @SqlType("array(T)") Block arrayBlock, | ||
| @SqlType("function(T, boolean)") SliceToBooleanFunction function) | ||
| { | ||
| boolean hasNullResult = false; | ||
| int positionCount = arrayBlock.getPositionCount(); | ||
| for (int i = 0; i < positionCount; i++) { | ||
| Slice element = null; | ||
| if (!arrayBlock.isNull(i)) { | ||
| element = elementType.getSlice(arrayBlock, i); | ||
| } | ||
| Boolean match = function.apply(element); | ||
| if (FALSE.equals(match)) { | ||
| return false; | ||
| } | ||
| if (match == null) { | ||
| hasNullResult = true; | ||
| } | ||
| } | ||
| if (hasNullResult) { | ||
| return null; | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
| @TypeParameter("T") | ||
| @TypeParameterSpecialization(name = "T", nativeContainerType = long.class) | ||
| @SqlType(StandardTypes.BOOLEAN) | ||
| @SqlNullable | ||
| public static Boolean allMatchLong( | ||
| @TypeParameter("T") Type elementType, | ||
| @SqlType("array(T)") Block arrayBlock, | ||
| @SqlType("function(T, boolean)") LongToBooleanFunction function) | ||
| { | ||
| boolean hasNullResult = false; | ||
| int positionCount = arrayBlock.getPositionCount(); | ||
| for (int i = 0; i < positionCount; i++) { | ||
| Long element = null; | ||
| if (!arrayBlock.isNull(i)) { | ||
| element = elementType.getLong(arrayBlock, i); | ||
| } | ||
| Boolean match = function.apply(element); | ||
| if (FALSE.equals(match)) { | ||
| return false; | ||
| } | ||
| if (match == null) { | ||
| hasNullResult = true; | ||
| } | ||
| } | ||
| if (hasNullResult) { | ||
| return null; | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
| @TypeParameter("T") | ||
| @TypeParameterSpecialization(name = "T", nativeContainerType = double.class) | ||
| @SqlType(StandardTypes.BOOLEAN) | ||
| @SqlNullable | ||
| public static Boolean allMatchDouble( | ||
| @TypeParameter("T") Type elementType, | ||
| @SqlType("array(T)") Block arrayBlock, | ||
| @SqlType("function(T, boolean)") DoubleToBooleanFunction function) | ||
| { | ||
| boolean hasNullResult = false; | ||
| int positionCount = arrayBlock.getPositionCount(); | ||
| for (int i = 0; i < positionCount; i++) { | ||
| Double element = null; | ||
| if (!arrayBlock.isNull(i)) { | ||
| element = elementType.getDouble(arrayBlock, i); | ||
| } | ||
| Boolean match = function.apply(element); | ||
| if (FALSE.equals(match)) { | ||
| return false; | ||
| } | ||
| if (match == null) { | ||
| hasNullResult = true; | ||
| } | ||
| } | ||
| if (hasNullResult) { | ||
| return null; | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
| @TypeParameter("T") | ||
| @TypeParameterSpecialization(name = "T", nativeContainerType = boolean.class) | ||
| @SqlType(StandardTypes.BOOLEAN) | ||
| @SqlNullable | ||
| public static Boolean allMatchBoolean( | ||
| @TypeParameter("T") Type elementType, | ||
| @SqlType("array(T)") Block arrayBlock, | ||
| @SqlType("function(T, boolean)") BooleanToBooleanFunction function) | ||
| { | ||
| boolean hasNullResult = false; | ||
| int positionCount = arrayBlock.getPositionCount(); | ||
| for (int i = 0; i < positionCount; i++) { | ||
| Boolean element = null; | ||
| if (!arrayBlock.isNull(i)) { | ||
| element = elementType.getBoolean(arrayBlock, i); | ||
| } | ||
| Boolean match = function.apply(element); | ||
| if (FALSE.equals(match)) { | ||
| return false; | ||
| } | ||
| if (match == null) { | ||
| hasNullResult = true; | ||
| } | ||
| } | ||
| if (hasNullResult) { | ||
| return null; | ||
| } | ||
| return true; | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Space after
T,beforeboolean=>T, boolean