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 - пара
Но можно определить отображение двумерного массива на одномерный 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]);
И, правда, есть уже. Вот что значит не спать по ночам…
“Не умножай сущности сверх необходимого”. (У.Оккам)
Не всегда перфекционизм полезен. В языках, предназначенных для обучения, он порой бывает и вреден, потому что в погоне за внешним лоском можно его сделать неохватным. Например, современный стандарт языка С++ насчитывает более 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)
. Что касается меня, я бы предпочел первый вариант: сначала значение эл-та, потом уже индекс(-ы).
Везде, где речь идет о массивах, обращение идет по первому параметру - элементу массива. Затем, при необходимости, указывается индекс. И это “правильный” порядок, когда параметр по умолчанию идет последним. Например, мы пишем a.Select(x->f(x)), если нам нужны сами элементы и “добираемся” до индексов, в формате a.Select((x,i)->f(x,i)). Что касается ElementsWithIndexes, само название говорит о том, что мы получаем элементы с индексами, а не наоборот.
@Admin: Если будет много свободного времени , предлагаю еще немного добавить “сахарку”. Довольно часто приходится проверять принадлежность некоторого значения интервалу, для чего его предварительно приходится запоминать в промежуточной переменной, а затем проверять обе границы в достаточно длинной конструкции булевского выражения, например
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))
Я также считаю текущий порядок обращения у IndexesOf <- (x,i)
более удачным. Но в том то и дело, что для ElementsWithIndexes
был почему-то определен обратный порядок (i,j,x)
, что на мой взгляд:
-
менее естественно – даже в названии ф-ции слово
Elements
стоит передIndexes
; -
менее удобно – обращаться к значению эл-та матрицы как
elem[2]
, а если позже будет добавлена поддержка трехмерных матриц – значение будет уже “по адресу”elem[3]
?; - нарушает единообразие в простом вопросе – порядке обращения к эл-там с индексами (хотя этот выбор был сделан на 2,5 месяца раньше, но, ИМХО, неудачно).
Именно поэтому, полагаю, было бы лучше переопределить порядок следования параметров в ElementsWithIndexes
также на (x,i,j)
. И там, и там – массивы, и там, и там – элементы с индексами. Единый подход, единая логика.
Неплохая идея, особенно в контексте лямбд, но тут возникает нюанс, включать или не включать границы диапазона? Соотв. для универсальности нужно либо делать 4+4 похожих функции+метода, либо городить доп. параметр, что получается уже довольно громоздко и не так удобно.
Вот настоящий сахарок был бы, если можно было бы сделать как в Питоне и Юльке:
a < b <= c >= d ...
@admin Такое вообще возможно? Хотя бы для 3-х операндов?
Уже все давно придумано, см. BETWEEN a AND b в языке SQL. Границы включаются.
Ну конечно возможно. Сделаем a.Between(b,c)
Я имел в виду возможность написания произвольных цепочек сравнений на уровне расширения синтаксиса языка, а не в виде кастомных функций…