From 175b3337afc1c8c87a09f3ba774c12cdd8656389 Mon Sep 17 00:00:00 2001 From: Rick Gutleber Date: Thu, 5 Dec 2024 09:52:32 -0500 Subject: [PATCH] fixed 'for_each_list' with generators also 'max_index' and 'min_index' now return all indices, not just the first --- rpn/makeHelp.py | 30 ++++++++++++++---------------- rpn/rpnOperators.py | 6 +++++- rpn/special/rpnList.py | 21 +++++++++++++++++---- rpn/test/testRPN.py | 27 ++++++++++++++++++++++----- rpn/util/rpnAliases.py | 2 ++ 5 files changed, 60 insertions(+), 26 deletions(-) diff --git a/rpn/makeHelp.py b/rpn/makeHelp.py index cbb38f7..4c82448 100644 --- a/rpn/makeHelp.py +++ b/rpn/makeHelp.py @@ -7012,7 +7012,7 @@ def makeCommandExample( command, indent=0, slow=False ): [ 'filter_show_index', 'filter_by_index', 'lambda', 'unfilter', 'filter_integers' ] ], 'filter_by_index' : [ -'functions', 'filters a list n using function k applied to the list indexes', +'functions', 'filters a list n using function k applied to the list indices', ''' The 'filter' operator uses a one-argument user-defined function to filter out elements based on whether or not the function returns 0 for each element. @@ -7052,7 +7052,7 @@ def makeCommandExample( command, indent=0, slow=False ): [ 'filter_by_index', 'lambda', 'unfilter', 'filter_integers', 'unfilter_ratio' ] ], 'filter_show_index' : [ -'functions', 'filters a list n using function k but returns a list of indexes of matching elements', +'functions', 'filters a list n using function k but returns a list of indices of matching elements', ''' The 'filter' operator uses a one-argument user-defined function to filter out elements based on whether or not the function returns 0 for each element. @@ -7266,7 +7266,7 @@ def makeCommandExample( command, indent=0, slow=False ): [ 'filter', 'unfilter_by_index', 'lambda', 'unfilter_show_index' ] ], 'unfilter_by_index' : [ -'functions', 'filters a list n using the inverse of function k applied to the list indexes', +'functions', 'filters a list n using the inverse of function k applied to the list indices', ''' The 'unfilter' operator uses a one-argument user-defined function to filter out elements based on whether or not the function returns 1 for each element. @@ -7292,7 +7292,7 @@ def makeCommandExample( command, indent=0, slow=False ): [ 'filter_by_index', 'lambda', 'unfilter', 'filter_integers', 'filter_ratio' ] ], 'unfilter_show_index' : [ -'functions', 'filters a list n using the inverse of function k and returns the indexes of matching elements', +'functions', 'filters a list n using the inverse of function k and returns the indices of matching elements', ''' The 'unfilter' operator uses a one-argument user-defined function to filter out elements based on whether or not the function returns 1 for each element. @@ -8212,7 +8212,7 @@ def makeCommandExample( command, indent=0, slow=False ): course, it necessary by trial-and-error to discover how long the chains can become and how big the numbers get. ''' + makeCommandExample( '-a30 10000 11000 range 100 find_palindrome lambda 0 x 0 element x 1 element ' - '0 equal if for_each_list max_index 10000 +' ) + ''' + '0 equal if for_each_list max_index 0 element 10000 +' ) + ''' ''' + makeCommandExample( '-a30 10911 55 find_palindrome' ) + ''' ''' + makeCommandExample( '-a20 89 25 find_palindrome' ), [ 'reversal_addition', 'is_kaprekar', 'reverse_digits' ] ], @@ -9549,11 +9549,10 @@ def makeCommandExample( command, indent=0, slow=False ): [ 'right', 'slice', 'sublist', 'random_element' ] ], 'max_index' : [ -'list_operators', 'returns the index of largest value in list n', +'list_operators', 'returns the indices of largest value in list n', ''' -This operator returns the index of the item in the list with the largest value. -If there are more than one item in the list with this largest value, then the -operator returns the index of the first occurrence of that value. +This operator returns the indices of the items in the list with the largest +value. ''', ''' ''' + makeCommandExample( '[ 8 10 9 3 4 2 5 1 7 6 ] max_index' ) + ''' @@ -9562,11 +9561,10 @@ def makeCommandExample( command, indent=0, slow=False ): [ 'min_index', 'element' ] ], 'min_index' : [ -'list_operators', 'returns the index of smallest value in list n', +'list_operators', 'returns the indices of smallest value in list n', ''' -This operator returns the index of the item in the list with the smallest value. -If there are more than one item in the list with this smallest value, then the -operator returns the index of the first occurrence of that value. +This operator returns the indices of the items in the list with the smallest +value. ''', ''' ''' + makeCommandExample( '[ 8 10 9 3 4 2 5 1 7 6 ] min_index' ) + ''' @@ -9592,7 +9590,7 @@ def makeCommandExample( command, indent=0, slow=False ): This operator is useful for applying an operator that returns a binary value on a list, and getting a summary of the results. -Indices are zero-based. +indices are zero-based. ''', ''' ''' + makeCommandExample( '[ 1 0 2 0 3 0 4 ] nonzero' ) + ''' @@ -9780,7 +9778,7 @@ def makeCommandExample( command, indent=0, slow=False ): 'slice' : [ 'list_operators', 'returns a slice of list a from starting index b to ending index c', ''' -Indices are zero-based, and the ending index is not included in the slice. +indices are zero-based, and the ending index is not included in the slice. This functionality echoes the Python slicing semantics. As in Python, a negative ending index represents counting backwards from the end of the list. @@ -9859,7 +9857,7 @@ def makeCommandExample( command, indent=0, slow=False ): This operator is useful for applying an operator that returns a binary value on a list, and getting a summary of the results. -Indices are zero-based. +indices are zero-based. ''', ''' ''' + makeCommandExample( '[ 1 0 2 0 3 0 4 ] zero' ) + ''' diff --git a/rpn/rpnOperators.py b/rpn/rpnOperators.py index 5279f32..14df156 100644 --- a/rpn/rpnOperators.py +++ b/rpn/rpnOperators.py @@ -1183,7 +1183,10 @@ def forEachList( listArg, func ): raise ValueError( '\'for_each_list\' expects a function argument' ) for i in listArg: - yield func.evaluate( i ) + if isinstance( i, RPNGenerator ): + yield func.evaluate( list( i ) ) + else: + yield func.evaluate( i ) def forEachListOperator( listArg, func ): @@ -1215,6 +1218,7 @@ def forEachListFilterOperator( listArg, func ): def forEachListUnfilterOperator( listArg, func ): return RPNGenerator( forEachListFilter( listArg, func, invert=True ) ) + #****************************************************************************** # # breakOnCondition diff --git a/rpn/special/rpnList.py b/rpn/special/rpnList.py index 3cc3a16..eefe228 100644 --- a/rpn/special/rpnList.py +++ b/rpn/special/rpnList.py @@ -305,7 +305,9 @@ def getIndexOfMaxOperator( args ): for i in args: if i > maximum: maximum = i - result = index + result = [ index ] + elif i == maximum: + result.append( index ) index += 1 @@ -322,13 +324,15 @@ def getIndexOfMaxOperator( args ): @argValidator( [ ListValidator( ) ] ) def getIndexOfMinOperator( args ): minimum = inf - result = -1 + result = [ ] index = 0 for i in args: if i < minimum: minimum = i - result = index + result = [ index ] + elif i == minimum: + result.append( index ) index += 1 @@ -1471,7 +1475,16 @@ def getListPowerSetOperator( n ): @argValidator( [ ListValidator( ), DefaultValidator( ) ] ) def findInListOperator( target, k ): try: - result = target.index( k ) + if isinstance( target, RPNGenerator ): + index = 0 + + for i in target: + if i == k: + return index + + index += 1 + else: + result = target.index( k ) except ValueError: return -1 diff --git a/rpn/test/testRPN.py b/rpn/test/testRPN.py index dcd61a3..b679ffd 100644 --- a/rpn/test/testRPN.py +++ b/rpn/test/testRPN.py @@ -597,6 +597,8 @@ def runArithmeticOperatorTests( ): expectResult( '5 is_square', 0 ) expectResult( '12 16j + is_square', 1 ) + expectResult( '-a103 2 100 range lambda x is_square not filter sqrt 10 99 ** * floor sum_digits sum', 40886 ) + # is_zero expectResult( '-1 is_zero', 0 ) expectResult( '0 is_zero', 1 ) @@ -1534,6 +1536,8 @@ def runCombinatoricsOperatorTests( ): # combinations expectEqual( '0 99 range lambda x 2 * x combinations sqr x 2 * x combinations + 2 / eval', '37967 oeis 100 left' ) + expectResult( '1 100 range lambda x 1 x range combinations eval flatten lambda x 1000000 greater filter count', 4075 ) + # compositions testOperator( '5 2 compositions' ) testOperator( '6 3 compositions' ) @@ -1622,6 +1626,9 @@ def runCombinatoricsOperatorTests( ): # debruijn_sequence testOperator( '4 3 debruijn_sequence' ) + # denomination_combinations + expectResult( '[ 1 2 5 10 20 50 100 200 ] 200 denomination_combinations', 73682 ) + # get_combinations testOperator( '1 5 range 2 get_combinations' ) @@ -2819,6 +2826,8 @@ def runLexicographyOperatorTests( ): testOperator( '-a30 10911 55 find_palindrome' ) testOperator( '180 200 range 10 find_palindrome -s1' ) + expectResult( '-a50 1 10000 range lambda x 30 find_palindrome 1 right 0 equals filter count', 249 ) + # get_base_k_digits expectEqual( '0 10000 range lambda x 2 get_base_k_digits sum x 10 get_base_k_digits sum equals filter', '37308 oeis 10000 filter_max' ) @@ -2853,8 +2862,10 @@ def runLexicographyOperatorTests( ): expectEqual( '-a420 1 2000 range lambda x fib x log10 floor 1 + get_right_digits x equals filter', '350 oeis 42 left 41 right' ) + expectResult( '2 7830457 10 10 ** powmod 28433 * 1 + 10 get_right_digits', 8739992577 ) + # get_right_truncations - testOperator( '123456789 get_right_truncations' ) + expectEqual( '123456789 get_right_truncations', '[ 123456789, 12345678, 1234567, 123456, 12345, 1234, 123, 12, 1 ]' ) # has_any_digits if g.primeDataAvailable: @@ -2978,13 +2989,14 @@ def runLexicographyOperatorTests( ): expectResult( '1234567890 is_pandigital', 1 ) expectResult( '1234567880 is_pandigital', 0 ) + expectEqual( '9001 9999 range lambda x 1 2 range * combine_digits is_pandigital filter', '[ 9267, 9273, 9327 ]' ) + # is_pandigital_zero expectResult( '3847596201 is_pandigital', 1 ) expectResult( '11335577998866442200 is_pandigital', 1 ) expectResult( '1234567890 is_pandigital', 1 ) expectResult( '1234567880 is_pandigital', 0 ) - # is_pddi testOperator( '1253 4 is_pddi' ) @@ -3028,6 +3040,8 @@ def runLexicographyOperatorTests( ): expectEqual( '123456 permute_digits', '30299 oeis 873 left 720 right' ) expectEqual( '1234567 permute_digits', '30299 oeis 5913 left 5040 right' ) + expectEqual( '1234567 permute_digits lambda x is_prime filter 1 right', '[ 7652413 ]' ) + if g.slowTests: expectEqual( '123456789 permute_digits 18 left', '50289 oeis 18 left' ) @@ -3076,6 +3090,8 @@ def runLexicographyOperatorTests( ): # sum_digits expectEqual( '0 1000 range sum_digits', '7953 oeis 1001 left' ) + expectResult( '-a300 [ 1 99 range 1 99 range ] permute_lists lambda x y ** sum_digits for_each max', 972 ) + if g.slowTests: expectEqual( '0 10000 range sum_digits', '7953 oeis 10001 left' ) @@ -3214,10 +3230,12 @@ def runListOperatorTests( ): expectResult( '1 10 range 5 left', [ 1, 2, 3, 4, 5 ] ) # max_index - expectResult( '1 10 range max_index', 9 ) + expectEqual( '1 10 range max_index', '[ 9 ]' ) + expectEqual( '[ 1 1 2 3 4 5 6 5 6 ] max_index', '[ 6 8 ]' ) # min_index - expectResult( '1 10 range min_index', 0 ) + expectEqual( '1 10 range min_index', '[ 0 ]' ) + expectEqual( '[ 1 1 2 3 4 5 6 5 6 1 ] min_index', '[ 0 1 9 ]' ) # nand_all testOperator( '[ 1 0 1 1 1 1 0 1 ] nand_all' ) @@ -5731,4 +5749,3 @@ def main( ): if __name__ == '__main__': main( ) - diff --git a/rpn/util/rpnAliases.py b/rpn/util/rpnAliases.py index 6a1078d..3b7761b 100644 --- a/rpn/util/rpnAliases.py +++ b/rpn/util/rpnAliases.py @@ -432,6 +432,8 @@ def dumpAliasesOperator( ): 'im' : 'imaginary', 'index_of_max' : 'max_index', 'index_of_min' : 'min_index', + 'indices_of_max' : 'max_index', + 'indices_of_min' : 'min_index', 'indian' : 'to_indian_civil', 'indian_civil' : 'to_indian_civil', 'indian_civil_name' : 'to_indian_civil_name',