Skip to content

Commit

Permalink
fixed 'for_each_list' with generators
Browse files Browse the repository at this point in the history
also 'max_index' and 'min_index' now return all indices, not just the first
  • Loading branch information
ConceptJunkie committed Dec 5, 2024
1 parent a307ea0 commit 175b333
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 26 deletions.
30 changes: 14 additions & 16 deletions rpn/makeHelp.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand All @@ -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.
Expand Down Expand Up @@ -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' ] ],
Expand Down Expand Up @@ -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' ) + '''
Expand All @@ -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' ) + '''
Expand All @@ -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' ) + '''
Expand Down Expand Up @@ -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.

Expand Down Expand Up @@ -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' ) + '''
Expand Down
6 changes: 5 additions & 1 deletion rpn/rpnOperators.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 ):
Expand Down Expand Up @@ -1215,6 +1218,7 @@ def forEachListFilterOperator( listArg, func ):
def forEachListUnfilterOperator( listArg, func ):
return RPNGenerator( forEachListFilter( listArg, func, invert=True ) )


#******************************************************************************
#
# breakOnCondition
Expand Down
21 changes: 17 additions & 4 deletions rpn/special/rpnList.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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

Expand Down Expand Up @@ -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

Expand Down
27 changes: 22 additions & 5 deletions rpn/test/testRPN.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 )
Expand Down Expand Up @@ -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' )
Expand Down Expand Up @@ -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' )

Expand Down Expand Up @@ -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' )
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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' )

Expand Down Expand Up @@ -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' )

Expand Down Expand Up @@ -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' )

Expand Down Expand Up @@ -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' )
Expand Down Expand Up @@ -5731,4 +5749,3 @@ def main( ):

if __name__ == '__main__':
main( )

2 changes: 2 additions & 0 deletions rpn/util/rpnAliases.py
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down

0 comments on commit 175b333

Please sign in to comment.