Помогает ли Linq сделать код понятнее или быстрее?
От: 0K Ниоткуда  
Дата: 31.07.10 10:42
Оценка: 1 (1) +2 -3 :)
По мотивам: http://rsdn.ru/forum/dotnet/3900028.flat.aspx
Автор: Dog
Дата: 30.07.10


Человек спросит, как с помощью Linq проверить упорядоченность массива, к примеру {1, 3, 5, 7, 9}.

Варианты ответа:

1.

var s = new[] {1, 3, 3, 7, 9};
var r = s.Aggregate(new {V=int.MinValue, C=0}, (a, val) => a.V < val ? new {V=val, C=a.C+1} : a).C == s.Length;


2.

var ascending = Enumerate()
                .Memoize(1)
                .Let(e => e.Zip(e.Skip(1), (a, b) => a < b))
                .All(x => x);


(это с применением Rx, кстати кто скажет что это такое?)

3.

var isAscending = xs.OrderBy(x => x).SequenceEqual(xs);



4.

var isAscending = xs.Replay(ys => ys.Zip(ys.Skip(1), (x, y) => x <= y), 1).All(x => x);


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

Мой вариант (долго не думал):

var numbers = new[] {1, 3, 5, 7, 9};
bool isAscending = true;

int temp = numbers[0];

for (int i = 1; i < numbers.Length; i++)
{
    if (temp > numbers[i])
    {
        isAscending = false;
        break;
    }

    temp = numbers[i];
}


Теперь скажите чей вариант быстрее и понятнее? Каков смысл в вашем Linq?
Re: Помогает ли Linq сделать код понятнее или быстрее?
От: FR  
Дата: 31.07.10 11:32
Оценка: 5 (3) +5
Здравствуйте, 0K, Вы писали:

0K>for (int i = 1; i < numbers.Length; i++)

0K>{
0K> if (temp > numbers[i])
0K> {
0K> isAscending = false;
0K> break;
0K> }

0K> temp = numbers[i];

0K>}
0K>[/c#]

0K>Теперь скажите чей вариант быстрее и понятнее? Каков смысл в вашем Linq?


Вот такой:

let rec f = function 
  | a::b::_  when a > b   -> false
  | h::t                  -> f t
  | _                     -> true


А Linq это так, жалкое подобие
Re: Помогает ли Linq сделать код понятнее или быстрее?
От: frogkiller Россия  
Дата: 31.07.10 14:43
Оценка: 1 (1) +4 :))) :)
Здравствуйте, 0K, Вы писали:

0K>По мотивам: http://rsdn.ru/forum/dotnet/3900028.flat.aspx
Автор: Dog
Дата: 30.07.10

0K>Человек спросит, как с помощью Linq проверить упорядоченность массива, к примеру {1, 3, 5, 7, 9}.

Прочитал исходное обсуждение, увидел:

Помня одно предыдущее значение, соедини последовательность с самой собой, смещённой с на один элемент вперёд, и проверь, что во всех парах левое значение меньше или равно правому.

Вспомнил классическое дадена тебе мышь &mdash; работай мышью... Долго думал...

Это всё очень красиво. Да-да, красиво, так говорит моё программерское чувство прекрасного. Но оно так же и бесполезно. Более того, оно вредно, потому что насмотрятся нубы на такое и будут делать всегда и везде, не думая ни о скорости, ни о выделении памяти, ни о побочных эффектах. А это печально.
Курица — это инструмент, с помощью которого одно яйцо производит другие.
Re[2]: Помогает ли Linq сделать код понятнее или быстрее?
От: The Lex Украина  
Дата: 31.07.10 19:00
Оценка: +1
Здравствуйте, frogkiller, Вы писали:

F>... и будут делать всегда и везде, не думая ни о скорости, ни о выделении памяти, ни о побочных эффектах. А это печально.


Печальнее всего еще и то, что в 9 случаях из 10 оно "красиво-нечитабельное". Попробуй потом такой код "поддержать"...

ЗЫ: задачи на логику на собеседованиях — зло! шибко "умный" программер придет — точно "умничать" будет.
Голь на выдумку хитра, однако...
Re: Помогает ли Linq сделать код понятнее или быстрее?
От: SpaceConscience  
Дата: 31.07.10 20:53
Оценка: +1 :))) :))) :))
0K>Мой вариант (долго не думал):

0K>
0K>var numbers = new[] {1, 3, 5, 7, 9};
0K>bool isAscending = true;

0K>int temp = numbers[0];

0K>for (int i = 1; i < numbers.Length; i++)
0K>{
0K>    if (temp > numbers[i])
0K>    {
0K>        isAscending = false;
0K>        break;
0K>    }

0K>    temp = numbers[i];
0K>}
0K>


Во-первых, у тебя оформление кода неправильное. Приближаться к "мирку" (к декларативному другому "мирку"), думаю, надо начать с оформления кода. Все надо стараться записать одной строчкой, переменным давать имена из одного-двух символов, никогда не указывать имена типов, главное правило: всегда плевать на эффективность ради краткости, ну и другие полезные практики:


var e = true; for (var i = 1; i < xs.Length; i++) if (xs[i-1] > xs[i]) e = false;
var isAscending = e;


Во, вот так к "мирку" уже ближе. Декларативнее. Приобщайся!
Собрался ставить минус? Да сам иди в жопу!

































































.
Re: Помогает ли Linq сделать код понятнее или быстрее?
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 31.07.10 22:36
Оценка: +1
Здравствуйте, 0K, Вы писали:

0K>Теперь скажите чей вариант быстрее и понятнее? Каков смысл в вашем Linq?

Твой в любом случае хуже всех, так как принимает массив, а не любую последовательность. Твой вариант является наименее общим при том что самый длинный.
В F# есть потрясающая функция Seq.pairwise, которая список [x1,x2,x3...] превращает в список пар [(x1,x2), (x2,x3)...] делает примерно тоже что в вариантах 2 и 4, только с одним итератором и совершенно не требует эмуляции ленивости с запоминанием.

Написать аналогичную функцию для C# несложно и при её использовании проверка на упорядоченность последовательности будет короткой, красивой и даже очевидной. При этом можно будет проверять на упорядоченность последовательность чисел, принимаемых по сети\доставаемых из бд, без сохранения всей последовательности в памяти.

Кроме того алгоритмы с Linq можно композировать, например для получения упорядоченных подпоследовательностей.
Re: Помогает ли Linq сделать код понятнее или быстрее?
От: IT Россия linq2db.com
Дата: 31.07.10 23:56
Оценка:
Здравствуйте, 0K, Вы писали:

0K>Каков смысл в вашем Linq?


Хотя бы в том, что твой пример без Linq упадёт на пустой последовательности.
Если нам не помогут, то мы тоже никого не пощадим.
Re[2]: Помогает ли Linq сделать код понятнее или быстрее?
От: FR  
Дата: 01.08.10 06:38
Оценка:
Здравствуйте, SpaceConscience, Вы писали:

SC>Во-первых, у тебя оформление кода неправильное. Приближаться к "мирку" (к декларативному другому "мирку"), думаю, надо начать с оформления кода. Все надо стараться записать одной строчкой, переменным давать имена из одного-двух символов, никогда не указывать имена типов, главное правило: всегда плевать на эффективность ради краткости, ну и другие полезные практики:


SC>

SC>var e = true; for (var i = 1; i < xs.Length; i++) if (xs[i-1] > xs[i]) e = false;
SC>var isAscending = e;

SC>


Много недостатков алгоритм даже не квадратичный, "if" вместо оператора "?" мутабельный e нет рекурсии, в общем незачет
Re[2]: Помогает ли Linq сделать код понятнее или быстрее?
От: vitasR  
Дата: 01.08.10 08:04
Оценка: +8
Здравствуйте, gandjustas, Вы писали:

0K>>Теперь скажите чей вариант быстрее и понятнее? Каков смысл в вашем Linq?

G>Твой в любом случае хуже всех, так как принимает массив, а не любую последовательность. Твой вариант является наименее общим при том что самый длинный.

его вариант на самом деле лучший, самый понятный и самых быстрых (только проверку на пустой массив надо приделать).
стремление к общности там где она нафиг не нужна — большая ошибка на самом деле.

G>В F# есть потрясающая функция Seq.pairwise, которая список [x1,x2,x3...] превращает в список пар [(x1,x2), (x2,x3)...] делает примерно тоже что в вариантах 2 и 4, только с одним итератором и совершенно не требует эмуляции ленивости с запоминанием.


работает, правда, все в разы медленнее, но кого нынче это волнует...
Re[3]: Помогает ли Linq сделать код понятнее или быстрее?
От: FR  
Дата: 01.08.10 08:48
Оценка: +1
Здравствуйте, vitasR, Вы писали:

R>его вариант на самом деле лучший, самый понятный и самых быстрых (только проверку на пустой массив надо приделать).


Самый понятный по моему рекурсивный, вот вариант на близком к шарпу D

pure auto f(int Arr[])
{
    if(Arr.length < 2)
        return true;
    
    if(Arr[0] > Arr[1])
        return false;
    
    return f(Arr[1 .. $]);
}


Тут сразу видна суть в императивном же варианте временная переменная ее заслоняет.
Ну и по эффективности из-за оптимизации хвостовой рекурсии этот вариант практически эквивалентен циклу:

    if(Arr.length < 2)
00402017  push        ebx  
00402018  push        esi  
00402019  mov         esi,dword ptr [esp+2Ch] 
0040201D  cmp         esi,2 
00402020  push        edi  
00402021  jae         main@f+21h (402031h) 
        return true;
00402023  pop         edi  
00402024  mov         eax,1 
00402029  pop         esi  
0040202A  pop         ebx  
0040202B  add         esp,20h 
0040202E  ret         8    
    
    if(Arr[0] > Arr[1])
00402031  mov         edx,ecx 
00402033  mov         ebx,dword ptr [edx] 
00402035  mov         eax,esi 
00402037  cmp         ebx,dword ptr [edx+4] 
0040203A  jle         main@f+37h (402047h) 
        return false;
0040203C  pop         edi  
0040203D  xor         eax,eax 
0040203F  pop         esi  
00402040  pop         ebx  
00402041  add         esp,20h 
00402044  ret         8    
    
    return f(Arr[1 .. $]);
00402047  lea         edi,[esi-1] 
0040204A  add         edx,4 
0040204D  mov         ecx,edx 
0040204F  mov         dword ptr [esp+0Ch],edi 
00402053  mov         esi,edi 
00402055  mov         dword ptr [esp+10h],edx 
00402059  cmp         dword ptr [esp+0Ch],2 
0040205E  jb          main@f+13h (402023h) 
00402060  jmp         main@f+21h (402031h)
Re[3]: Помогает ли Linq сделать код понятнее или быстрее?
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 01.08.10 12:02
Оценка:
Здравствуйте, vitasR, Вы писали:

R>Здравствуйте, gandjustas, Вы писали:


0K>>>Теперь скажите чей вариант быстрее и понятнее? Каков смысл в вашем Linq?

G>>Твой в любом случае хуже всех, так как принимает массив, а не любую последовательность. Твой вариант является наименее общим при том что самый длинный.

R>его вариант на самом деле лучший, самый понятный и самых быстрых (только проверку на пустой массив надо приделать).


Скажи по-русски что такое отсортированный массив.

R>стремление к общности там где она нафиг не нужна — большая ошибка на самом деле.

Обоснуй.

G>>В F# есть потрясающая функция Seq.pairwise, которая список [x1,x2,x3...] превращает в список пар [(x1,x2), (x2,x3)...] делает примерно тоже что в вариантах 2 и 4, только с одним итератором и совершенно не требует эмуляции ленивости с запоминанием.


R>работает, правда, все в разы медленнее, но кого нынче это волнует...

Конечно, не волнует. Время компьютера дешево, а время программиста дорого.
Re[2]: Помогает ли Linq сделать код понятнее или быстрее?
От: 0K Ниоткуда  
Дата: 01.08.10 12:15
Оценка: +1 :)))
Здравствуйте, gandjustas, Вы писали:

G>Твой в любом случае хуже всех, так как принимает массив, а не любую последовательность.


Для тех, кто не уловил принцип:

bool isOrdered = true;

enumerator.MoveNext();
var temp = enumerator.Current;

while (enumerator.MoveNext())
{
    if (temp > enumerator.Current)
    {
        isOrdered = false;
        break;
    }

    temp = enumerator.Current;
}


Разницы нет последовательность или тип, который нужно листать с помощью вызова функции. Вообще в 99% массивы предпочтительнее -- все равно все хранится в памяти.

G>Твой вариант является наименее общим при том что самый длинный.


Да? А так:

bool o = true; e.MoveNext();
var temp = e.Current;
while (e.MoveNext()){ if (temp > e.Current) { o = false; break; } temp = e.Current; }


Мальчик. Объясняю пока жив: главное понятность кода а не во сколько байт ты его втиснул.
Re[2]: Помогает ли Linq сделать код понятнее или быстрее?
От: 0K Ниоткуда  
Дата: 01.08.10 12:17
Оценка:
Здравствуйте, IT, Вы писали:

IT>Хотя бы в том, что твой пример без Linq упадёт на пустой последовательности.


А ваш пример на Linq для пустой последовательности выдаст true или false? Значение для пустой последовательности не определено -- это зависит от логики программы. По этому проверку я не включал.
Re[3]: Помогает ли Linq сделать код понятнее или быстрее?
От: 0K Ниоткуда  
Дата: 01.08.10 12:19
Оценка:
Здравствуйте, vitasR, Вы писали:

R>его вариант на самом деле лучший, самый понятный и самых быстрых (только проверку на пустой массив надо приделать).


Кстати, философский вопрос. При передаче пустого массива нужно вернуть true или false?
Re[3]: Помогает ли Linq сделать код понятнее или быстрее?
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 01.08.10 12:43
Оценка:
Здравствуйте, 0K, Вы писали:

0K>Здравствуйте, gandjustas, Вы писали:


G>>Твой в любом случае хуже всех, так как принимает массив, а не любую последовательность.


0K>Разницы нет последовательность или тип, который нужно листать с помощью вызова функции. Вообще в 99% массивы предпочтительнее -- все равно все хранится в памяти.


Это ты где такую шутку прочитал?
99% данных обычно программа получает извне.
Re[4]: Помогает ли Linq сделать код понятнее или быстрее?
От: FR  
Дата: 01.08.10 12:49
Оценка:
Здравствуйте, 0K, Вы писали:

0K>Кстати, философский вопрос. При передаче пустого массива нужно вернуть true или false?


true, также и для массива из одного элемента.
Re[3]: Помогает ли Linq сделать код понятнее или быстрее?
От: FR  
Дата: 01.08.10 12:53
Оценка:
Здравствуйте, 0K, Вы писали:

0K>главное понятность кода а не во сколько байт ты его втиснул.


Понятность понятие субъективное.
Декларативный код обычно выигрывает в понятности, особенно если для этого есть примитивы, в Linq их правда похоже нет.
Re[4]: Помогает ли Linq сделать код понятнее или быстрее?
От: Yarik_L  
Дата: 01.08.10 12:55
Оценка: :)
Здравствуйте, 0K, Вы писали:

0K>Кстати, философский вопрос. При передаче пустого массива нужно вернуть true или false?

Если взять любой упорядоченный массив, то очевидно что все массивы, получающиеся из исходного вычеркиванием отдельных элементов, также будут упорядоченными. Значит и пустой массив обязан быть таковым
Re[5]: Помогает ли Linq сделать код понятнее или быстрее?
От: 0K Ниоткуда  
Дата: 01.08.10 12:59
Оценка:
Здравствуйте, FR, Вы писали:

0K>>Кстати, философский вопрос. При передаче пустого массива нужно вернуть true или false?


FR>true, также и для массива из одного элемента.


Для массива из одного элемента -- согласен. А если вообще элементов нет?
Re[4]: Помогает ли Linq сделать код понятнее или быстрее?
От: 0K Ниоткуда  
Дата: 01.08.10 13:04
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Это ты где такую шутку прочитал?

G>99% данных обычно программа получает извне.

Ну да, и записывает их в ОЗУ. А раз в ОЗУ, то лучше массив.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.