Прошло несколько дней и вот- “Только бледнолицый может дважды наступить на одни и те же грабли” (с)
Рискуя навлечь на себя праведный гнев “Отцов-Основателей” все же помещу еще раз описание проблемы. Скажем так, в назидание другим бледнолицым.
Наткнулся на школьную задачу, где предлагалось в произвольном целочисленном массиве элементы с НЕЧЕТНЫМИ номерами упорядочить по возрастанию их значений. И стало интересно получить решение с максимальным использованием возможностей версии 3.1, т.е. “написать покороче”.
Первый шаг - перейти к динамическим массивам, т.е. принять к сведению, что работать будем с ЧЕТНЫМИ индексами из-за нумерации от 0, а не с помощью чисел натурального ряда. Т.е. надо обрабатывать элементы с индексами i=0,2,…2k, i<=n-1 для массива из n элементов.
Дальнейшие шаги: выделить упомянутые выше элементы, упорядочить их по возрастанию, поместить в последовательность и заместить элементами этой последовательности нужные элементы в исходном массиве.
Была написана программа, которая дала удивительные результаты и которую затем я щедро снабдил трассировочным выводом. Вот эта программа:
// PascalABC.NET 3.1, сборка 1174 от 22.02.2016
begin
var n:=ReadInteger('n=');
var a:=ArrRandom(n,10,99);
Writeln('a: ',a);
var b:=Range(0,n-1,2).Select(i->a.ElementAt(i)).Sorted;
Writeln('b: ',b);
var i:=0;
while i<=n-1 do begin
var j:=i div 2;
Writeln('Проход по циклу номер ',j+1);
Writeln('a[',i,']=',a[i],', b[',j,']=',b.ElementAt(j));
a[i]:=b.ElementAt(j);
Writeln('a[',i,']=',a[i],', b[',j,']=',b.ElementAt(j));
Writeln('a: ',a);
i+=2
end;
Writeln('a: ',a)
end.
И вот выдача:
n= 10
a: [33,13,51,91,89,70,30,89,72,79]
b: [30,33,51,72,89]
Проход по циклу номер 1
a[0]=33, b[0]=30
a[0]=30, b[0]=30
a: [30,13,51,91,89,70,30,89,72,79]
Проход по циклу номер 2
a[2]=51, b[1]=30
a[2]=30, b[1]=30
a: [30,13,30,91,89,70,30,89,72,79]
Проход по циклу номер 3
a[4]=89, b[2]=30
a[4]=30, b[2]=30
a: [30,13,30,91,30,70,30,89,72,79]
Проход по циклу номер 4
a[6]=30, b[3]=30
a[6]=30, b[3]=30
a: [30,13,30,91,30,70,30,89,72,79]
Проход по циклу номер 5
a[8]=72, b[4]=72
a[8]=72, b[4]=72
a: [30,13,30,91,30,70,30,89,72,79]
a: [30,13,30,91,30,70,30,89,72,79]
Хорошо видно, что посредством метода .ElementAt() из последовательности b извлекаются, мягко говоря, странные значения. Ну и результат, соответственно… в мусорную корзину.
Переход к массивам посредством добавления .ToArray радикально все меняет и программа сразу становится работоспособной:
// PascalABC.NET 3.1, сборка 1174 от 22.02.2016
begin
var n:=ReadInteger('n=');
var a:=ArrRandom(n,10,99);
Writeln('a: ',a);
var b:=Range(0,n-1,2).Select(i->a.ElementAt(i)).Sorted.ToArray;
Writeln('b: ',b);
var i:=0;
while i<=n-1 do begin
var j:=i div 2;
Writeln('Проход по циклу номер ',j+1);
Writeln('a[',i,']=',a[i],', b[',j,']=',b[j]);
a[i]:=b[j];
Writeln('a[',i,']=',a[i],', b[',j,']=',b[j]);
Writeln('a: ',a);
i+=2
end;
Writeln('a: ',a)
end.
Трассировка показывает, что все происходит строго так, как положено.
n= 10
a: [89,83,59,21,29,54,31,86,73,44]
b: [29,31,59,73,89]
Проход по циклу номер 1
a[0]=89, b[0]=29
a[0]=29, b[0]=29
a: [29,83,59,21,29,54,31,86,73,44]
Проход по циклу номер 2
a[2]=59, b[1]=31
a[2]=31, b[1]=31
a: [29,83,31,21,29,54,31,86,73,44]
Проход по циклу номер 3
a[4]=29, b[2]=59
a[4]=59, b[2]=59
a: [29,83,31,21,59,54,31,86,73,44]
Проход по циклу номер 4
a[6]=31, b[3]=73
a[6]=73, b[3]=73
a: [29,83,31,21,59,54,73,86,73,44]
Проход по циклу номер 5
a[8]=73, b[4]=89
a[8]=89, b[4]=89
a: [29,83,31,21,59,54,73,86,89,44]
a: [29,83,31,21,59,54,73,86,89,44]
Последовательность в самостоятельном виде использовать практически нельзя: пресловутая “обезьяна с гранатой” рядом с последовательностями отдыхает. Т.е. мы должны понимать, что практически любой метод, примененный к массиву, силится превратить массив в последовательность (и обычно это ему удается!) и забыв прилепить в конце строки .ToArray мы сразу же получаем объект, который в будущем (возможно, уже в следующем операторе) сделает нам “бо-бо”.
Вот к чему ведет “ленивость”, если ей потакать…