@@ -34,6 +34,7 @@ $(T2 commonPrefix,
34
34
`commonPrefix("parakeet", "parachute")` returns `"para"`.)
35
35
$(T2 endsWith,
36
36
`endsWith("rocks", "ks")` returns `true`.)
37
+ $(T2 extrema, `extrema([2, 1, 3, 5, 4])` returns `[1, 5]`.)
37
38
$(T2 find,
38
39
`find("hello world", "or")` returns `"orld"` using linear search.
39
40
(For binary search refer to $(REF SortedRange, std,range).))
@@ -3684,7 +3685,7 @@ Note:
3684
3685
3685
3686
See_Also:
3686
3687
3687
- $(LREF maxElement), $(REF min, std,algorithm,comparison), $(LREF minCount),
3688
+ $(LREF extrema), $(LREF maxElement), $(REF min, std,algorithm,comparison), $(LREF minCount),
3688
3689
$(LREF minIndex), $(LREF minPos)
3689
3690
*/
3690
3691
auto minElement (alias map = (a => a), Range )(Range r)
@@ -3865,7 +3866,7 @@ Note:
3865
3866
3866
3867
See_Also:
3867
3868
3868
- $(LREF minElement), $(REF max, std,algorithm,comparison), $(LREF maxCount),
3869
+ $(LREF extrema), $(LREF minElement), $(REF max, std,algorithm,comparison), $(LREF maxCount),
3869
3870
$(LREF maxIndex), $(LREF maxPos)
3870
3871
*/
3871
3872
auto maxElement (alias map = (a => a), Range )(Range r)
@@ -4035,6 +4036,132 @@ if (isInputRange!Range && !isInfinite!Range &&
4035
4036
assert (maxElement(arr) == S(145 ));
4036
4037
}
4037
4038
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
+
4038
4165
// minPos
4039
4166
/**
4040
4167
Computes a subrange of `range` starting at the first occurrence of `range`'s
0 commit comments