@@ -34,6 +34,7 @@ $(T2 commonPrefix,
3434 `commonPrefix("parakeet", "parachute")` returns `"para"`.)
3535$(T2 endsWith,
3636 `endsWith("rocks", "ks")` returns `true`.)
37+ $(T2 extrema, `extrema([2, 1, 3, 5, 4])` returns `[1, 5]`.)
3738$(T2 find,
3839 `find("hello world", "or")` returns `"orld"` using linear search.
3940 (For binary search refer to $(REF SortedRange, std,range).))
@@ -3684,7 +3685,7 @@ Note:
36843685
36853686See_Also:
36863687
3687- $(LREF maxElement), $(REF min, std,algorithm,comparison), $(LREF minCount),
3688+ $(LREF extrema), $(LREF maxElement), $(REF min, std,algorithm,comparison), $(LREF minCount),
36883689 $(LREF minIndex), $(LREF minPos)
36893690*/
36903691auto minElement (alias map = (a => a), Range )(Range r)
@@ -3865,7 +3866,7 @@ Note:
38653866
38663867See_Also:
38673868
3868- $(LREF minElement), $(REF max, std,algorithm,comparison), $(LREF maxCount),
3869+ $(LREF extrema), $(LREF minElement), $(REF max, std,algorithm,comparison), $(LREF maxCount),
38693870 $(LREF maxIndex), $(LREF maxPos)
38703871*/
38713872auto maxElement (alias map = (a => a), Range )(Range r)
@@ -4035,6 +4036,132 @@ if (isInputRange!Range && !isInfinite!Range &&
40354036 assert (maxElement(arr) == S(145 ));
40364037}
40374038
4039+ /* * Returns an array of the minimum and maximum element in `r`.
4040+ * Performs `< 3n/2` comparisons, unlike the naive `< 2n`.
4041+ * Params:
4042+ * r = The range to traverse.
4043+ */
4044+ // TODO alias map = a => a
4045+ ElementType! Range [2 ] extrema (Range )(Range r)
4046+ if (isInputRange! Range && ! isInfinite! Range )
4047+ in (! r.empty)
4048+ {
4049+ static if (isRandomAccessRange! Range && hasLength! Range )
4050+ {
4051+ if (r.length == 1 )
4052+ return [r[0 ], r[0 ]];
4053+
4054+ typeof (return ) result;
4055+ size_t i;
4056+ if (r.length & 1 ) // odd
4057+ {
4058+ result = [r[0 ], r[0 ]];
4059+ i = 1 ;
4060+ }
4061+ else
4062+ {
4063+ result = (r[0 ] < r[1 ]) ? [r[0 ], r[1 ]] : [r[1 ], r[0 ]];
4064+ i = 2 ;
4065+ }
4066+ // iterate pairs
4067+ const imax = r.length;
4068+ for (; i != imax; i += 2 )
4069+ {
4070+ // save work
4071+ if (r[i] < r[i+ 1 ])
4072+ {
4073+ if (r[i] < result[0 ])
4074+ result[0 ] = r[i];
4075+ if (r[i+ 1 ] > result[1 ])
4076+ result[1 ] = r[i+ 1 ];
4077+ }
4078+ else
4079+ {
4080+ if (r[i+ 1 ] < result[0 ])
4081+ result[0 ] = r[i+ 1 ];
4082+ if (r[i] > result[1 ])
4083+ result[1 ] = r[i];
4084+ }
4085+ }
4086+ return result;
4087+ }
4088+ else
4089+ {
4090+ auto first = r.front;
4091+ r.popFront;
4092+ if (r.empty)
4093+ return [first, first];
4094+
4095+ typeof (return ) result = (first < r.front) ? [first, r.front] : [r.front, first];
4096+ // iterate pairs
4097+ while (true )
4098+ {
4099+ r.popFront;
4100+ if (r.empty)
4101+ return result;
4102+ first = r.front;
4103+ r.popFront;
4104+ if (r.empty)
4105+ {
4106+ if (first < result[0 ])
4107+ result[0 ] = first;
4108+ else if (first > result[1 ])
4109+ result[1 ] = first;
4110+ return result;
4111+ }
4112+ // save work
4113+ if (first < r.front)
4114+ {
4115+ if (first < result[0 ])
4116+ result[0 ] = first;
4117+ if (r.front > result[1 ])
4118+ result[1 ] = r.front;
4119+ }
4120+ else
4121+ {
4122+ if (r.front < result[0 ])
4123+ result[0 ] = r.front;
4124+ if (first > result[1 ])
4125+ result[1 ] = first;
4126+ }
4127+ }
4128+ }
4129+ }
4130+
4131+ // /
4132+ @safe unittest
4133+ {
4134+ assert (extrema([5 ,2 ,9 ,4 ,1 ]) == [1 , 9 ]);
4135+ }
4136+
4137+ @safe unittest
4138+ {
4139+ assert (extrema([8 ,3 ,7 ,4 ,9 ]) == [3 , 9 ]);
4140+ assert (extrema([1 ,5 ,3 ,2 ]) == [1 , 5 ]);
4141+ assert (extrema([2 ,3 ,3 ,2 ]) == [2 , 3 ]);
4142+
4143+ import std.range ;
4144+ assert (iota(2 , 5 ).extrema == [2 , 4 ]);
4145+ assert (iota(3 , 7 ).retro.extrema == [3 , 6 ]);
4146+
4147+ import std.internal.test.dummyrange ;
4148+ foreach (DummyType; AllDummyRanges)
4149+ {
4150+ DummyType d;
4151+ assert (d.extrema == [1 , 10 ]);
4152+ }
4153+
4154+ version (StdRandomTests)
4155+ foreach (i; 0 .. 1000 )
4156+ {
4157+ import std.random ;
4158+ auto arr = generate! (() => uniform(0 , 100 )).takeExactly(uniform(1 , 10 )).array;
4159+ auto result = arr.extrema;
4160+ assert (result[0 ] == arr.minElement);
4161+ assert (result[1 ] == arr.maxElement);
4162+ }
4163+ }
4164+
40384165// minPos
40394166/**
40404167Computes a subrange of `range` starting at the first occurrence of `range`'s
0 commit comments