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

omp-разработчик ушел. Мы можем как-то поддерживать omp, а можем просто его запретить

Так и есть. Компилятор включается после директив. Если хотите чтобы директива не действовала - сотрите доллар

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

a.Select((x,i)->(x,i)).Where(x->x[0]>30).Select(x->x[1])

с последующим выбором нужных элементов, но и ранее упомянутые расширения входят в эту модель посредством ,First и .Last

Сложно ли добавить расширение IndexesOf(), возвращающее последовательность всех найденных индексов или -1, если таковых не найдено? Понятно, что не очень удобно проверять на s[0]=-1, но уж лучше так…

Лучше бы сразу пару .AllIndexesOf(value) / .AllIndexesBy(selector) или IndicesOf() / .IndicesBy() по аналогии с .Max / .MaxBy()

Как насчет того, чтобы добавить свойства Low/High к массивам? Так, вроде бы, немного изящнее: for var i:=a.Low to a.High do чем for var i:=Low(a) to High(a) do

Или вообще реализовать для них метод Indexes(dim:=0):sequence of integer foreach var i in a.Indexes do

Что думаете?

Так есть же это

Прекрасное предложение. Сделал так:

begin
  var a := Arr(1,2,3,4,5);
  foreach var i in a.Indexes do
    Print(a[i]);
  Println;
  
  foreach var i in a.IndexesOf(x->Odd(x)) do
    Print(a[i]);
  Println;
    
  foreach var i in a.IndexesOf((x,i)->Odd(x) and (i<4)) do
    Print(a[i]);
end.

Интересно еще что-то подобное сделать с двумерными массивами. Жаль, нет технической возможности определить как метод расширения операцию индексирования для двумерных массивов: a[t], где t - пара

1 лайк

Но можно определить отображение двумерного массива на одномерный a[i,j] = a[i*a.ColCount+j] Есть и обратное отображение. Можно попробовать это использовать.

Может, все-таки, лучше сделать пару a.IndexesOf(value) и a.IndexesBy(sеlector)? Возможно я ошибаюсь, но мне кажется, что суффикс Of в .Net обычно относится к параметрам-значениям, а не ф-циям выбора. Чтобы писать просто:

var a := Arr(1,5,5,4,5);
foreach var i in a.IndexesOf(5) do
    Print(a[i]);

вместо

foreach var i in a.IndexesOf(x->x=5) do
    Print(a[i]);

При этом все продвинутые фильтры будут, как обычно, через By():

foreach var i in a.IndexesBy((x,i)->Odd(x) and (i<4)) do
    Print(a[i]);

И, правда, есть уже. Вот что значит не спать по ночам… :dizzy_face:

“Не умножай сущности сверх необходимого”. (У.Оккам)

Не всегда перфекционизм полезен. В языках, предназначенных для обучения, он порой бывает и вреден, потому что в погоне за внешним лоском можно его сделать неохватным. Например, современный стандарт языка С++ насчитывает более 1000 страниц текста. Стоит ли к этому идти?

Я думаю, ошибаетесь. Во-первых, окончание Of есть только в паре методов, во-вторых, окончание By относится к тому, что элемент проектируется на некоторое другое значение, как правило, более простое. Допустим, в GroupBy(s->s.course) студент проектируется на курс, и группировка идет по курсам. Так что, я думаю, Вы явно другое хотели

“проектируется” = “проецируется”? Если везде в .NET так, как Вы говорите, то соглашусь.

Проверил – все отлично работает, спасибо! Меня только смущает немного выбранный здесь порядок обращения к элементам массива (value,index), поскольку для эл-тов матриц совсем недавно был выбран обратный порядок:

function ElementsWithIndexes<T>(Self: array [,] of T): sequence of (integer,integer,T); extensionmethod;

т.е. (index1,index2,value).

Мне кажется, это следует гармонизировать, пока не поздно. Либо принять везде как стандарт (x,i) / (x,i,j), либо наоборот (i,x) / (i,j,x). Что касается меня, я бы предпочел первый вариант: сначала значение эл-та, потом уже индекс(-ы).

2 лайка

Везде, где речь идет о массивах, обращение идет по первому параметру - элементу массива. Затем, при необходимости, указывается индекс. И это “правильный” порядок, когда параметр по умолчанию идет последним. Например, мы пишем a.Select(x->f(x)), если нам нужны сами элементы и “добираемся” до индексов, в формате a.Select((x,i)->f(x,i)). Что касается ElementsWithIndexes, само название говорит о том, что мы получаем элементы с индексами, а не наоборот.

@Admin: Если будет много свободного времени :slight_smile:, предлагаю еще немного добавить “сахарку”. Довольно часто приходится проверять принадлежность некоторого значения интервалу, для чего его предварительно приходится запоминать в промежуточной переменной, а затем проверять обе границы в достаточно длинной конструкции булевского выражения, например

  var s:=ReadlnString('>');
  var p:=Pos('*',s);
  if (p>=1) and (p<=s.Length div 2) then ...

Было бы приятно видеть функцию Between(x,a,b), возвращающую true, если x принадлежит [a,b]. И расширение вида x.Between(a,b). Тогда код мог бы стать прозрачнее и короче:

var s:=ReadlnString('>');
if Between(Pos('*',s),1,s.Length div 2) then ...

Кроме того, это сократило бы лямбды и сделало бы их выразительнее, например a.Where(x->x.Between(p,q))

1 лайк

Я также считаю текущий порядок обращения у IndexesOf <- (x,i) более удачным. Но в том то и дело, что для ElementsWithIndexes был почему-то определен обратный порядок (i,j,x), что на мой взгляд:

  • менее естественно – даже в названии ф-ции слово Elements стоит перед Indexes;
  • менее удобно – обращаться к значению эл-та матрицы как elem[2], а если позже будет добавлена поддержка трехмерных матриц – значение будет уже “по адресу” elem[3]?;
  • нарушает единообразие в простом вопросе – порядке обращения к эл-там с индексами (хотя этот выбор был сделан на 2,5 месяца раньше, но, ИМХО, неудачно).

Именно поэтому, полагаю, было бы лучше переопределить порядок следования параметров в ElementsWithIndexes также на (x,i,j). И там, и там – массивы, и там, и там – элементы с индексами. Единый подход, единая логика.

1 лайк

Неплохая идея, особенно в контексте лямбд, но тут возникает нюанс, включать или не включать границы диапазона? Соотв. для универсальности нужно либо делать 4+4 похожих функции+метода, либо городить доп. параметр, что получается уже довольно громоздко и не так удобно.

Вот настоящий сахарок был бы, если можно было бы сделать как в Питоне и Юльке: a < b <= c >= d ...

@admin Такое вообще возможно? Хотя бы для 3-х операндов?

Уже все давно придумано, см. BETWEEN a AND b в языке SQL. Границы включаются.

Ну конечно возможно. Сделаем a.Between(b,c)

Я имел в виду возможность написания произвольных цепочек сравнений на уровне расширения синтаксиса языка, а не в виде кастомных функций…