Версия PascalABC.NET 3.5

В теории LINQ позволяет записать любой алгоритм в 1 строку. Вот только в случае простых чисел и прочих элементарных и часто вызываемых алгоритмов - лучше всё равно расписывать по старинке, потому что иначе будет огромная потеря производительности.

Ну, на всяк - приведите тот код в 1 строчку и алгоритм решета Эратосфена на старом паскале.
При переводе на новый всегда есть что улучшить, хотя бы те же for var и элементарные оптимизации для .Net, что увижу из такого - скажу.

1 лайк

Любую программу можно в 1 строчку написать

Но это кстати спорно. Вообще программа будет хотя бы 3 строчки, потому что ещё begin и end., поэтому я сказал алгоритм.

А ещё можно ли это считать 1 строчкой?))

begin
  Arr(0).ForEach(_o->begin %любой алгоритм% end);
end.

По моему это уродливое форматирование, поэтому однострочной программой лучше считать ту - в которой всего 1 end. Не begin, потому что case-end и т.п. в 1 строчку - тоже кривое форматирование.

Однако я уже не помню что за алгоритм, потому что это было давно, но однажды от нечего делать я решил записать какой то сложный алгоритм однострочным, основываясь на этом же определении (1 end на программу).

И, в общем, после пары часов говнокоденья я закончил логически доказав что всех функций Linq и PABCSystem не хватает и это невозможно написать без введения дополнительной переменной. То есть написать можно только в 2 строчки.

1 лайк

Боюсь представить, кому такое может потребоваться, если предполагать, что реализуемый алгоритм не уровня Hello world.

Которые можно поместить в одну строку. Только, опять же вопрос - зачем?

А вообще вроде вспомнил. Не тот самый алгоритм но смысл.
Вот пример не решаемой задачи:

Найдите сумму минимума и максимума массива

Как создавать массив - не важно. С клавиатуры/рандомом. Смысл в том что не сохраняя этот массив в переменную - вычислить и минимум и максимум сразу не выйдет.

P.S. Ну и чо уж мне, вот сразу и решение не решаемого:

Осторожно, может вызывать выпадение глаз
begin
  Arr&<sequence of integer>(
    ArrRandomInteger(30).Println
  ).Cycle
  .Zip(Arr(
    Func&<sequence of integer, integer>(s->s.Min),
    Func&<sequence of integer, integer>(s->s.Max)
  ), (s,f)->f(s))
  .Sum.Println;
end.

И даже почти работает, эх, если бы ещё не падало)))

1 лайк

Стандартный алгоритм поиска простых чисел

begin Range(2,1000).Where(x -> Range(2,Round(sqrt(x))).All(i->x mod i <> 0)).Print; end.

Решето Эратосфена

const N = 100; var i, k : integer; A : array[2…N] of boolean; begin for i:= 2 to N do A[i]:= True; k:= 2; while kk <= N do begin if A[k] then begin i:= kk; while i <= N do begin A[i]:= False; i:= i + k end; end; k:= k + 1 end; for i:= 2 to N do if A[i]= True then writeln(i); end.

Длинновато по-старому…

1 лайк

Известный еще по языку С “синдром одной строки” явление нехорошее. В программе должно быть ровно столько строк, сколько требуется, а погоня за упаковкой в строку любого алгоритма - она сущеглупое действо.

5 лайков

Ну уже хотя бы через SeqWhile, а то sqrt, ещё и Round…

Код надо выделять так:

```
код
```

При чём на строчках с ``` - больше ничего быть не должно, а то они ломаются.
Отредактируйте ваше сообщение чтоб нормально выглядело.

По алгоритму - у вас по крайней мере не хватает 1 break-а, нету самой проверки на mod и лишние

Ну, если я понял правильно смысл:

function ВсеПростыеДо(n: integer): sequence of integer;
begin
  var res := new boolean[n-1]; // True если не простое
  for var i := 2 to n do
  begin
    var k := 2;
    
    while k*k<i do
    begin
      if not res[k-2] and (i mod k = 0) then
      begin
        res[i-2] := true;
        break;
      end;
      k += 1;
    end;
    
    if not res[i-2] then yield i;
  end;
end;

begin
  ВсеПростыеДо(ReadInteger).PrintLines;
end.

В принципе - можно использовать HashSet чтоб сократить использование памяти. То есть хранить только простые числа, и использовать .Contains . Простые числа достаточно хаотично располагаются, поэтому сложность .Contains будет близка к O(1).

Вот более короткое решение, которое для n = 10 млн быстрее примерно в 50 раз.

Для n = 100 млн оно работало 3.3 с, а предложенное @Sun_Serega - 289 c, т. е. уже в 87 раз дольше.

begin
  var n := 100000000;
  Milliseconds;
  var p := ArrFill(n + 1, True);
  (p[0], p[1]) := (False, False);
  for var i := 2 to Trunc(Sqrt(n)) do
    if p[i] then
    begin
      var j := i * i;
      while j <= n do
      begin
        p[j] := False;
        j += i
      end
    end;
//    for var i := 2 to p.High do;
//      if p[i] then
//        Print(i)
 MillisecondsDelta.Println;
 p.Where(t-> t).Count.Println;
end.
1 лайк

Я тут копался в компиляторе, и вот что оказывается дня 3 назад добавили:

begin
  var (a,b) := (2,3);
  var min: integer;
  min := if a<b then a else b;
  Print(min)
end.

Это круто, хотя не понятно зачем, если ?: уже есть.

@Admin а может, раз уже делаете подобное, разрешите и такое?:

var x := case key of
  1: 'abc';
  2: 'def';
end;

В отличии от if-then-else, которое только более длинный аналог ?:, case возвращающий значение очень помог бы сократить код и сделать его красивее.

3 лайка

А вообще, теперь когда я над этим подумал (в очередной раз переписывая значительную часть OpenCLABC) - для lock такой синтаксис будет ещё полезнее:

begin
  var lst := new List<byte>;
  var d := new Dictionary<word,real>;
  ...
  var a := lock lst do lst.ToArray;
  var d := lock d do d[0];
end.

Через дополнительную переменную выглядит не красиво и объёмно. А ещё тип переменной не авто-выводится, то есть ещё и больно:

begin
  var lst := new List<byte>;
  var d := new Dictionary<word,real>;
  ...
  
  var a: array of byte;
  lock lst do a := lst.ToArray;
  
  var val: real;
  lock d do val := d[0];
  
end.

Это идиома тернарного оператора. Она изящнее и лучше смотрится для начинающих, чем чужеродный для Паскаля тернарный оператор. Тот же if - then- else, только возвращающий значение. Очень логично. Был в Алгол-60 и 68, на базе которых Вирт сочинял свой Паскаль, но Вирт был сторонником минимализма, и кастрировал алголы, зачастую выплескивая ребенка вместе с водой.

В Питоне есть подобная конструкция

Ван Россум натаскал в Питон помаленьку из других языков.

var min := if (a < b) a else b

Отвратительно читается, имхо. В Питоне по-другому:

min = a if a < b else b

А если еще и автовывода типа нету…

Вот код в Kotlin:

fun foo(param: Int) {
    val result = if (param == 1) {
        "one"
    } else if (param == 2) {
        "two"
    } else {
        "three"
    }
}
1 лайк

Вот в питоне как раз отвратительно, потому что не симметрично. Если вы выражениях не по 1 букве (a и b) - вариант который сейчас на много читабельнее. И работает по аналогии с обычным if и с другими языками. Это только в питоне так раскорячиваться надо.

3 лайка

Во-первых, не надо перевирать. Запись будет иметь вид: var min := if a < b then a else b; Без дурацких скобок и с нормальным паскалевским then. Переводим на русский: “переменной min присвоить: если a < b, то a, иначе b” Все логично. А теперь переведем на русский питоновское: "min присвоить a, если a < b, иначе b.

Питон - это образец изъянений в стиле магистра Йоды: “а присвоить если a меньше b минимуму нужно иначе b”

2 лайка

Согласен, что такое выражение

var min := if a < b then a else b

читается гораздо лучше, чем такое

var min := if (a < b) a else a

Разве я соврал? И также я не сказал, что в Питоне лучше, просто там иначе =)

2 лайка

Мы делаем то же самое.