Partition - это не совсем то. Есть масса задач, когда надо протабулировать функцию от некоторого a c шагом h и до тех пор, пока очередная итерация аргумента не превысит b. А partition в общем случае изменит точки табуляции, потому что он не шаг держит, а разбивает весь интервал на равные отрезки. Например, попробуйте выполнить табуляцию для a от 0.3 с шагом 0.031 до 0.5, соблюдая именно шаг - в этой ситуации partition “ни о чем”.
В общем, это всего лишь аналог достаточно распространенного оператора цикла for x:=a to b step h (в нотации BASIC) или for x:=a step h until b еще в АЛГОЛ-60.
Хочется как-то “свернуть” цикл вида
var x:=a;
while x<=b do begin
...
x+=h
end;
Тот, на который нас обрёк Н.Вирт, кастрировав Алгол-60.
P.S. Не так давно переводил с Алгол-60 (там прекрасная библиотека исходников) процедуру обращения матрицы методом Гаусса-Жордана и когда встретился фрагмент
вслух сказал очень непристойное слово, имея в виду как раз Н.Вирта…
Не удивит: я давно (лет так 45 примерно) знаком с фокусами неточного представления чисел в ЭВМ. Поскольку начинал работать с техникой, где даже ассемблера еще не было - только восьмеричные коды.
Если у меня шаг нецелый, то пусть в меня сколько угодно кидают камни, но я поступаю так:
begin
var (x,h):=(1.0,0.1);
while x<=2+h/2 do begin
Print(x);
x+=h
end
end.
Но реплика об очень непристойном слове для случая целочисленных параметров цикла все равно остается…
Выкрутился - потому что моделировал алголовские циклы (см. выше), а прямой замены нет, за что Н.Вирту “спасибо”. С другой стороны, нельзя в очередной раз не сказать настоящее спасибо разработчикам за прекрасные возможности, заложенные в эту версию языка.
Кстати, кто-нибудь может мне объяснить, почему условие в виде if Result.CompareTo(a[i]) > 0 всегда возвращает true (и, соответственно, результатом функции будет просто последний элемент массива, а не ожидаемый минимальный), а если записать его в инверсии: if a[i].CompareTo(Result) < 0, то все работает как положено?
function MinElem<T>(a: array of T): T;
where T: IComparable<T>;
begin
Result := a[0];
for var i := 1 to a.Length - 1 do
if Result.CompareTo(a[i]) > 0 then
Result := a[i];
end;
@admin На мой взгляд функции LastIndexMin и LastIndexMax в вариантах с дополнительным параметром start вообще сейчас реализованы некорректно – они производят поиск в первой половине массива, т.е. от начала и до позиции start, а не с позиции start и до конца, как ожидается из их описания. Ну, или тогда замените имя start на finishAt, например.
function LastIndexMin<T>(Self: array of T; start: integer): integer; extensionmethod; where T: System.IComparable<T>;
begin
var min := Self[start];
Result := start;
for var i:=start-1 downto 0 do
if Self[i].CompareTo(min)<0 then
begin
Result := i;
min := Self[i];
end;
end;
От позиции start до начала. То есть, мы стартуем с конца. По-моему, всё верно
Ну не знаю, Станислав Станиславович, может Вы, конечно, выросли на Ближнем Востоке ;), но для большинства людей естественный и ожидаемый порядок обработки последовательных данных – по нарастающей слева-направо / сверху-вниз, то есть в данном случае от нулевого элемента массива (или любого другого произвольного = start) и до последнего. Проход в обратном порядке – это всего лишь внутренняя особенность реализации конкретной функции, которая обычному пользователю не видна.
Давайте рассуждать так: с точки зрения пользователя есть одна функция LastIndexMax c необязательным параметром start на тот случай, если он захочет начать обработку не с 0-го элемента, а с любого другого. Если он опустит этот параметр (т.е. логически для него начнет с нуля), обработается весь массив. Но если он явно напишет a.LastIndexMax(0) – также начать с нуля, то будет обработан только нулевой элемент и результат всегда будет = 0. Когнитивный диссонанс обеспечен!
Я указываю только на очевидное, на мой взгляд, противоречие между описанием/заголовком ф-ции (и соотв. ожидаемым результатом) и фактическим результатом. Разумеется, имеет право на существование и текущая реализация, если в ней больше практическго смысла, но в таком случае описание нужно скорректировать, например, так:
/// Возвращает индекс последнего максимального элемента, начиная с позиции 0 вплоть до позиции stopAt
function LastIndexMax<T>(Self: array of T; stopAt: integer): integer; extensionmethod;
Интересно, что думают на этот счет другие коллеги?
Как я и говорил, такой подход вполне допустим, если он соответствует описанию функции. В данном случае – полностью соответствует. Обратите внимание на разницу:
/// Осуществляет поиск указанного объекта и возвращает отсчитываемый от нуля индекс последнего вхождения в диапазоне элементов списка System.Collections.Generic.List'1,
начиная с первого элемента и до позиции с заданным индексом.
'/// Возвращаемое значение: Отсчитываемый от нуля индекс последнего вхождения элемента
function LastIndexOf(item: T; index: integer): integer;
/// Возвращает индекс последнего минимального элемента начиная с позиции start
function LastIndexMax<T>(Self: array of T; start: integer): integer; ...
Пускай даже параметр будет называться нейтрально – index, лишь бы не start в данном случае, хотя stopAt здесь был бы интуитивно понятнее, ИМХО.
З.Ы. Кстати, вторая строчка из Comment-Doc (Возвращаемое значение:) у меня не отображается в подсказке Intellisense, так и должно быть?