Замечания и предложения

Возможно не самое важное дополнение, но имеет место быть при “богатстве” разных мониторов в школах, это дать возможность изменять шрифт в Окне вывода. Пока это можно сделать только в настройках Редактора. Будет не лишним, если после изменения размера шрифта, шрифт поменяется и в Окне вывода.

4 лайка

Да, для демонстрации на проекторе тоже очень неудобно бывает, что в окне вывода шрифт фиксирован.

Можно использовать Ctrl+колёсико мыши. Кстати, в студии в окне Output оно не работает

Да, это хороший вариант для дома или рабочего места. Но выше о том, что когда один раз настроил для всех и забыл. С “колёсиком” после перезапуска приложения всё дефолтное…

Заметил у версии 3.2 в сборке 1344 от 22.11.2016 появление возможностей для работы с двумерными массивами. И это очень радует: наконец-то появляется что-то, помимо одинокого MatrixRandom (Внимание! Теперь он стал именоваться MatrRandom).

Желающие могут испытать удовольствие от новшеств, посмотрев, к примеру, вот на этот код:

begin
  var m:=ReadInteger('Количество строк в массиве:');
  var n:=ReadInteger('Количество столбцов в массиве:');
  Writeln('*** Исходный массив A[',m,',',n,'] ***');
  var a:=MatrRandom(m,n,-50,50); a.Println(5);
  Writeln(5*a.ColCount*'-');
  for var i:=0 to a.ColCount-1 do Write(a.Col(i).Sum:5)
end.
Пример работы
Количество строк в массиве: 5
Количество столбцов в массиве: 10
 *** Исходный массив A[5,10] ***
  -24   -1  -17   29   20  -28  -12   38   32  -36
   19   50  -17   21   -9  -13    4   28   20   37
   -2    6   18   16  -28  -38  -28   17  -20  -13
   39   -8  -39  -33   -9   12  -47   23   50  -25
    8   -7    3   11    1  -12   14   47  -41  -44
--------------------------------------------------
   40   40  -52   44  -25  -79  -69  153   41  -81

Прекрасно, что эти сдвиги есть. Но, как известно, натура людская такова, что человеку всегда мало, чего бы ему не дать))) Может быть, я еще не все “раскопал”. Может быть, еще не все реализовано, что задумано. Но что просматривается в качестве определенных недостатков, если оставить лишь то, что есть.

  1. Недоступны полноценные объекты “строка” и “столбец”.

Я могу извлечь i-ю строку посредством A.Row(i) или j-й столбец посредством A.Col(i). Но чтобы даже просто их перебрать, нужно писать цикл, подобный вышеприведенному. А хочется писать что-то вроде foreach var r in A.Rows do … Очень хочется получить векторы var aR:=A.GetRows и var aC:=A.GetCols, чтобы потом работать с ними в цепочках. А также слайсы по типу A.GetRows[3:1:2]

  1. Нет инициализации матриц фиксированными значениями.

Хотя бы единичная матрица была.

  1. Невозможно без цикла с явным перебором всех элементов заменить всю строку или столбец содержимым некоего вектора соответствующей длины.
  1. Крайне желательно иметь Swap для пары строк/столбцов
1 лайк

Сделал MatrFill и MatrGen. Т.е. var a := MatrGen(n,n,(i,j)->i=j?1:0)

  1. Недоступны полноценные объекты “строка” и “столбец”.

Непонятно, как Вы хотите. Что такое полноценные. То что Вы дальше пишете - это вообще последовательности строк. Скажите, что Вы хотите для одной строки. Не забывайте, что возвращается копия в виде одномерного массива. Я могу сделать еще a.RowSequence, возвращающую последовательность.

По поводу A.GetRows - да, возвращается последовательность строк. Но что есть каждая строка? Одномерный массив? Но тогда это много копий. По-существу, копии всей матрицы в виде одномерных массивов строк. Поясните.

Слайсы - ну давайте это позже. Слайсы только на чтение - ну зачем они?

  1. Невозможно без цикла с явным перебором всех элементов заменить всю строку или столбец содержимым некоего вектора соответствующей длины.

Приведите пример, как Вы хотите. Если длины будут различаться?

SwapRows - да, это без проблем. Но - приведите пример распространенной задачи

Превосходно!

Возможно, на меня оказали влияние мощные средства, которые предоставляет VBA Microsoft Excel для работы с прямоугольными областями ячеек, которые отображаются на двумерные массивы. Представляется удобным иметь некие объекты классов “строка” и “столбец” с тем, чтобы ходить по ним в циклах, подобным foreach.

foreach Row in a.Rows do begin
  Writeln('Строка ',Row.RowIndex,', max=',Row.Max,', элемент ',Row.IndexMax)
  foreach Elem in Row do
    if Elem<2*Row.Max then a[Elem.Row,Elem.Col]:=0
  end;

И ColSequence тогда тоже. Есть много задач с экономическим уклоном, где операции делают по столбцам таблицы.

Наверно, это я рановато. Давайте про это одновременно со слайсами, потому что речь к тому шла, чтобы научиться одной операцией вырезать из массива подмассив - строку, столбец или прямоугольник, содержащий строки или столбцы, возможно несмежные и выбираемые некой лямбдой или с шагом. Например, сформировать из матрицы новый массив, состоящий из строк, содержащих не менее трех нулевых элементов. Или любой иной бред.

Да очень просто. Пусть есть матрица 6х4. Требуется строку 3 заменить содержимым вектора длины 4. Простое поэлементное копирование, но хорошо бы одной операцией, а не циклом. В более расширенном варианте можно бы сделать проверку длины вектора. Если длина больше, остальные элементы вектора не используются, если меньше - замещаются только содержащиеся в векторе. То же и по колонке.

И SwapCols. Пример? Да хотя бы обращение матрицы, решение СЛАУ. Там полно перестановок строк.

Ошибку с зацикливанием исправили

А как с обобщением типов? Планируется или останется только integer?

А я там не вижу ошибки. Вы напишите более развёрнуто, а то по скриншоту непонятно. С моей точки зрения, там матрица вещественная, хотя Вы пишете про что-то целое

Сделал a.RowSeq(k) и a.ColSeq(k), возвращающие строку и столбец в виде последовательности. Это позволяет не копировать строку и столбец в одномерный массив как было при вызове a.Row(k) Но нельзя обращаться по индексу

Изменил действие a.Rows и a.Cols - теперь a.Rows возвращает последовательность строк, строка при этом является последовательностью элементов. То есть, a.Rows возвращает sequence of sequence of T

Пример использования:

begin
  var m := MatrGen(5,7,(x,y)->(x+1)*(y+1));
  m.Println;
  
  foreach var c in m.Cols do
  begin
    foreach var x in c do
      Write(x:5);
    Writeln;
  end;
    
  m.Cols.Println(NewLine);  
  
  m.Cols.Foreach(procedure(c)->c.Println);
end.
1 лайк

Как только версия будет доступна, побегу тестить! ))))

Так доступна уже!

Так я не могу одновременно тут читать и проверять обновление)))

Да, в сборке 1350 все уже все работает, как надо.

Да, m.Rows.Select(x->x.Sum).Println; - это уже бомбочка! ))) Правда, Intellisence пока еще не понимает m.Rows, но это дело наживное.

Уже понимает

1 лайк
"И когда волки были сыты, а овцы - целы, возникла проблема: как накормить овец?"

Попытался как-то уйти от циклов для работы с индексами в матрицах. Но не тут-то было! Нельзя без цикла ничего в матрице заменить - ни строку, ни столбец. Казалось бы, простейшая вещь - умножение матриц

// PascalABC.NET 3.2, сборка 1353 от 27.11.2016
// Внимание! Если программа не работает, обновите её версию!

begin
  // (var l, var m, var n):=(3,5,2); - нельзя, нежданчик от компилятора
  var l,m,n:integer;
  (l,m,n):=(3,5,2);
  var A:=MatrRandom(l,m,1,50); A.Println(5); Writeln;
  var B:=MatrRandom(m,n,1,50); B.Println(5); Writeln;
  var C:=MatrFill(l,n,0);
  for var i:=0 to l-1 do
    for var j:=0 to n-1 do
      C[i,j]:=A.Row(i).Zip(B.Col(j),(x,y)->x*y).Sum;
  C.Println(5)
end.

Фактически, удалось избавиться только от внутреннего цикла, да и то, весьма громоздко. Гора родила мышь? Нет, произведение матриц можно вычислить и вывести без традиционных циклов. И это уже очень большой шаг вперед!

// PascalABC.NET 3.2, сборка 1353 от 27.11.2016
// Внимание! Если программа не работает, обновите её версию!

begin
  var l,m,n:integer;
  (l,m,n):=(3,5,2);
  var A:=MatrRandom(l,m,1,50); A.Println(5); Writeln;
  var B:=MatrRandom(m,n,1,50); B.Println(5); Writeln;
  foreach var Ra in A.Rows do begin
    foreach var Cb in B.Cols do
      Write(Ra.Zip(Cb,(x,y)->x*y).Sum:5);
    Writeln
    end;
end.

А проблема лишь в том, что наши векторы Ra, Cb “не помнят”, кто их породил, т.е. не наследуют номер строки и столбца от своего родителя. И проблема эта заставляет всю красоту тускнеть. Рискну высказать крамольную мысль. А давайте на секунду предположим, что порожденные векторы на один элемент длиннее и в этом последнем элементе содержат как раз тот самый номер? Мы привыкли уже любой динамический массив длины k “пробегать” от 0 до k-1, Так оно и останется. А об элементе с индексом будем вспоминать, если он понадобится. Можно и по-другому поступить наверно, например, ввести расширение/свойство/метод, дающие доступ к индексу родителя, но не знаю, не сломает ли это всю внутреннюю реализацию.

Мы получили “в лице” a.Rows и a.Cols “последовательность последовательностей”. Но не получили никакого инструментария для работы с ними, за исключением перебора посредством foreach. Честно скажу, пока небогато. Как вынуть из них конкретную строку/столбец? Ведь когда эти a.Rows и a.Cols могут быть наиболее полезны? Когда нужно будет по матрице “погулять” в разрезе строк или столбцов". Например, отобрать столбцы с хотя бы одним отрицательным значением и заменить такие столбцы в исходной матрице нулевыми. Столбцы-то отфильтруем, а дальше? Связь с исходной матрицей разорвана, а если бы и была, нужно еще уметь занулять нужные столбцы в матрице. Опять пришли к тому, что беда от отсутствия памяти о родителе. Что-то надо с этим делать…

Во многих случаях будет нужно что-то вроде ReplaceRow(C,Vx,i), замещающее i-ю строку матрицы С элементами Vx. Соответственно и ReplaceCol(C,Vy,j).

Есть вопрос с довольно частой операцией транспонирования матриц. Если сделать расширение M.Transpose, это будет удобно, потому что позволит встраивать такие конструкции в цепочки. Я не представляю, как сейчас сделать транспонирование матрицы без традиционных циклов.

И - сортировка. В задачах часто встречается требование упорядочить матрицу по конкретному столбцу или колонке. Опять же, по возрастанию или убыванию.

Конечно, мы помним, что если возникнут расширения, порождающие матрицы, надо оговорить, что происходит при присваивании типа var P:=C.Transpose. Мне кажется, в данном случае должно иметь место копирование, в отличии от операции A:=B, работающей по принципу “Cам дурак!”, т.е. просто создающей ссылку, поскольку уже было сказано, что надо в подобных случаях писать A:=Copy(B), а не стрелять себе в ногу.

Безусловно, было бы очень здорово перегрузить (только если хотя бы один из операндов - матрица) операции сложения, вычитания и умножения, но возможно это породит громоздкие коды (при умножении одним из операндов может быть матрица, вектор или скаляр, плюс нужно контролировать соблюдение размеров) и такое есть смысл реализовать в каком-то внешнем модуле, подключаемом по uses.

1 лайк

Ну, так например:

begin
  var l,m,n: integer;
  (l,m,n) := (3,5,2);
  var A := MatrRandom(l,m,1,50); A.Println(5); Writeln;
  var B := MatrRandom(m,n,1,50); B.Println(5); Writeln;
  C := MatrGen(l,n,(i,j)->A.Row(i).Zip(B.Col(j),(x,y)->x*y).Sum);
  C.Println(5)
end.
1 лайк