Skip to content
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

Add PositionMaximum and PositionMinimum #956

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/ref/lists.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1416,6 +1416,7 @@ The latter can be done also using <Ref Func="ListWithIdenticalEntries"/>.
<#Include Label="PositionNthOccurrence">
<#Include Label="PositionSorted">
<#Include Label="PositionSet">
<#Include Label="PositionMaximum">
<#Include Label="PositionProperty">
<#Include Label="PositionsProperty">
<#Include Label="PositionBound">
Expand Down
40 changes: 40 additions & 0 deletions lib/list.gd
Original file line number Diff line number Diff line change
Expand Up @@ -869,6 +869,44 @@ DeclareGlobalFunction( "PositionSet" );
DeclareOperation( "PositionProperty", [ IsList, IsFunction ] );
DeclareOperation( "PositionProperty", [ IsList, IsFunction, IS_INT ] );

#############################################################################
##
#O PositionMaximum( <list> [, <func>] )
#O PositionMinimum( <list> [, <func>] )
##
## <#GAPDoc Label="PositionMaximum">
## <ManSection>
## <Func Name="PositionMaximum" Arg='list [, func]'/>
## <Func Name="PositionMinimum" Arg='list [, func]'/>
##
## <Description>
## returns the position of maximum (with <Ref Func="PositionMaximum"/>) or
## minimum (with <Ref Func="PositionMinimum"/>) entry in the list <A>list</A>.
## If a second argument <A>func</A> is passed, then return instead the position
## of the largest/smallest entry in <C>List( <A>list</A> , <A>func</A> )</C>.
## If several entries of the list are equal
## to the maximum/minimum, the first such position is returned.
## <P/>
## <Example><![CDATA[
## gap> PositionMaximum( [2,4,-6,2,4] );
## 2
## gap> PositionMaximum( [2,4,-6,2,4], x -> -x);
## 3
## gap> PositionMinimum( [2,4,-6,2,4] );
## 3
## gap> PositionMinimum( [2,4,-6,2,4], x -> -x);
## 2
## ]]></Example>
## <P/>
## <Ref Func="Maximum" Label="for various objects"/> and
## <Ref Func="Minimum" Label="for various objects"/>
## allow you to find the maximum or minimum element of a list directly.
## </Description>
## </ManSection>
## <#/GAPDoc>
##
DeclareGlobalFunction( "PositionMaximum" );
DeclareGlobalFunction( "PositionMinimum" );

#############################################################################
##
Expand Down Expand Up @@ -1717,6 +1755,7 @@ DeclareOperation( "StableSortParallel",
## gap> Maximum( [1,2], [0,15], [1,5], [2,-11] );
## [ 2, -11 ]
## ]]></Example>
## To get the index of the maximum element use <Ref Func="PositionMaximum"/>
## </Description>
## </ManSection>
## <#/GAPDoc>
Expand Down Expand Up @@ -1759,6 +1798,7 @@ DeclareGlobalFunction( "Maximum" );
## gap> Minimum( [ 1, 2 ], [ 0, 15 ], [ 1, 5 ], [ 2, -11 ] );
## [ 0, 15 ]
## ]]></Example>
## To get the index of the minimum element use <Ref Func="PositionMinimum"/>
## </Description>
## </ManSection>
## <#/GAPDoc>
Expand Down
68 changes: 68 additions & 0 deletions lib/list.gi
Original file line number Diff line number Diff line change
Expand Up @@ -1571,6 +1571,74 @@ InstallMethod( PositionProperty,
end );


#############################################################################
##
#M PositionMaximum(<list>[, <func>]) . position of the largest element
#M PositionMinimum(<list>[, <func>]) . position of the smallest element
##

InstallGlobalFunction( PositionMaximum,
function ( args... )
local list, func, i, bestval, bestindex, ival;

if Length(args) < 1 or Length(args) > 2
or not(IsList(args[1]))
or (Length(args) = 2 and not(IsFunction(args[2]))) then
ErrorNoReturn("Usage: PositionMaximum(<list>, [<func>])");
fi;

list := args[1];
if Length(args) = 2 then
func := args[2];
else
func := IdFunc;
fi;

bestindex := fail;
for i in [ 1 .. Length( list ) ] do
if IsBound( list[i] ) then
ival := func ( list[ i ] );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we be concerned about performance and treat the 1-argument case differently to avoid calling IdFunc on each element of the list?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IdFunc is very fast. It might speed it up a little, but at the cost of twice as much, almost identical, code.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, then let's fix GAPDoc elements and use IdFunc in both functions, and merge this...


if not( IsBound(bestval) ) or ival > bestval then
bestval := ival;
bestindex := i;
fi;
fi;
od;
return bestindex;
end );

InstallGlobalFunction( PositionMinimum,
function ( args... )
local list, func, i, bestval, bestindex, ival;

if Length(args) < 1 or Length(args) > 2
or not(IsList(args[1]))
or (Length(args) = 2 and not(IsFunction(args[2]))) then
ErrorNoReturn("Usage: PositionMinimum(<list>, [<func>])");
fi;

list := args[1];
if Length(args) = 2 then
func := args[2];
else
func := IdFunc;
fi;

bestindex := fail;
for i in [ 1 .. Length( list ) ] do
if IsBound( list[i] ) then
ival := func ( list[ i ] );

if not( IsBound(bestval) ) or ival < bestval then
bestval := ival;
bestindex := i;
fi;
fi;
od;
return bestindex;
end );

#############################################################################
##
#M PositionsProperty(<list>,<func>) . positions of elements with a property
Expand Down
36 changes: 36 additions & 0 deletions tst/testinstall/listgen.tst
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,42 @@ gap> MinimumList( [ 1, 2 .. 20 ] );
1
gap> MinimumList( [ 10, 8 .. 2 ] );
2
gap> PositionMaximum([2,4,6,4,2,6]);
3
gap> PositionMaximum([2,4,6,4,2,6], x -> -x);
1
gap> PositionMinimum([2,4,6,4,2,6]);
1
gap> PositionMinimum([2,4,6,4,2,6], x -> -x);
3
gap> PositionMaximum();
Error, Usage: PositionMaximum(<list>, [<func>])
gap> PositionMaximum(2);
Error, Usage: PositionMaximum(<list>, [<func>])
gap> PositionMaximum([1,2], 2);
Error, Usage: PositionMaximum(<list>, [<func>])
gap> PositionMaximum([1,2], x -> x, 2);
Error, Usage: PositionMaximum(<list>, [<func>])
gap> PositionMinimum();
Error, Usage: PositionMinimum(<list>, [<func>])
gap> PositionMinimum([1,2], 2);
Error, Usage: PositionMinimum(<list>, [<func>])
gap> PositionMinimum(2);
Error, Usage: PositionMinimum(<list>, [<func>])
gap> PositionMinimum([1,2], x -> x, 2);
Error, Usage: PositionMinimum(<list>, [<func>])
gap> PositionMaximum([]);
fail
gap> PositionMaximum([,,,]);
fail
gap> PositionMaximum([2,,4,,6]);
5
gap> PositionMinimum([2,,4,,6]);
1
gap> PositionMinimum([,,,]);
fail
gap> PositionMinimum([]);
fail
gap> String( l );
"[ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 ]"
gap> String( [ 1 .. 10 ] );
Expand Down