Здравствуйте, Павел Кузнецов, Вы писали:
ПК>Классная вышла "оптимизация". Например, в случае LinkedList мы получим совершенно избыточное копирование в массив только для того, чтоб пройтись по нему в обратном порядке.
Если это станет узким метсом, то не долго написать специализацию и для него:
static IEnumerable<T> Revers<T>(IEnumerable<T> iter)
{
IList<T> list = iter as IList<T>;
if (list != null)
{
for (int i = list.Count - 1; i >= 0; i--)
yield return list[i];
}
else
{
ICollection<T> collection = iter as ICollection<T>;
if (collection != null)
{
T[] array = new T[collection.Count];
collection.CopyTo(array, 0);
for (int i = array.Length; i >= 0; i--)
yield return array[i];
}
else
{
LinkedList<T> ll = iter as LinkedList<T>;
if (ll != null)
{
LinkedListNode<T> node = ll.Last;
while (node != null)
{
yield return node.Value;
node = node.Previous;
}
yield break;
}
Stack<T> stack = new Stack<T>();
foreach (T value in iter)
stack.Push(value);
foreach (T value in stack)
yield return value;
}
}
}
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Оданко, что характерно ты тоже не угадал, что выдаст данный код. Я взял на себя смелость его скопилировать и запустить... результат оказался следующим:
7 6 8 5 0 1
1 0 5 8 6 7
И это в трех соснах. Что же будет когда кода будет по больше.
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Sinclair, Вы писали:
S>Ну, это уж да. Если секс — то непременно полноценный. Давайте на всякий случай доопределим на примитивном односвязном списке суперинтерфейс курсора с тридцатью двумя методами. В шестнадцати насладимся сексом с реализацией Prev с учетом SetRange и фильтрации, а остальные шестнадцать будут возвращать NotSupported. Чтобы и пользователь нашего курсора тоже вкусил полноценного секса. С всенепременным деторождением.
Я плякаль... И почему нельзя ставить много смайликов сразу?
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, vdimas, Вы писали:
V>Пишу сервер приложений на C#, как минимум в половине библиотечных методов над коллекциями 2 доп. виртуальных вызова на итерацию сопоставимы с затратами на тело цикла. Стараюсь использовать по-возможности for(), получаю примерно вдвое выигрыш.
VD>>Я согласен, что бывают места где нужна гаранитрованно высокая скорость. В таких местах я и СТЛ на пушочный выстрел не подпущу, так как мне нужен полный контроль, а не зависимость от реализации. Но таких мест доли процента. А 99% кода обычно — это мало влияющий на общую производительность код. За то его 99% и именно его рыхлость и не понятность приводит к тому, что программы становится мучительно тяжкло поддерживать иразвивать.
V>Скажем так, основная масса действительно сложного и ресурсоемкого кода должна содержаться в background-е, в некоем фреймворке, заточенном под прикладную область. Наверху должна оставаться верхушка айсберга, приятная глазу прикладного программиста.
Точно.
V>Мне как приходится писать первое. И хотя основная масса кода (зачастую "линейная", т.е. практически без циклов) содержится в прикладной части, эффективность системы в целом определяет все-таки background.
Общая эффективность системы определяется общей архитектурой. for или foreach, даже в background, не могут влиять на это кардинально. Если же они всё таки начинают влияют, то нужно поднимать вопрос о смене приоритетов.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Если нам не помогут, то мы тоже никого не пощадим.
Что характерно, в отличие от комбинации двух find_if и for_each, неудачно почти дословно повторяющей условие задачи, сразу видно, что именно хотел выразить этим автор
> Оданко, что характерно ты тоже не угадал, что выдаст данный код. <...>
Это прискорбные последствия "усложнения" последовательности после написания сообщения.
> И это в трех соснах. Что же будет когда кода будет по больше.
Ты искренне считаешь, что дело в коде? Я ориентировался по условию задачи, а не по коду.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
VladD2,
> ПК> Например, проход по подпоследовательности (связного) списка в обратном порядке не требует ничего копировать в промежуточный массив. > > Ага. Как в прочем и не является последовательным.
А какой же он? Параллельный, или, быть может, случайный?..
> ПК>Нет, я в основном говорю о (связных) списках, которые по определению обладают последовательным доступом. > > Связанные списки вообще особный разговор. Но в данном случае они потребуют полного перебора для прогрутки. И возможность прохода в обратную сторону без копирования будет доступна только при условии, что связанный список двунаправляенный.
Естественно. Это вполне удачно передается концепцией двунаправленных итераторов STL.
> Что еже не хило привязывает к реализацииям списоков или понижает эффективность.
Не к реализациям, а к концепциям. Естественно, обратный проход возможен только при наличии соответствующего итератора. Проблема в том, что энумераторы .Net не позволяют и этого.
> ПК> Классная вышла "оптимизация". Например, в случае LinkedList мы получим совершенно избыточное копирование в массив только для того, чтоб пройтись по нему в обратном порядке. > > Да, но это не так уж и накладно с одной стороны <...>
Ну, ты ж назвал это оптимизацией... Мне только оставалось правильно расставить кавычки
> для прямого однонаправленного итератора в СТЛ прийдется делать тоже самое. Ну, бывает же, что итератор действительно извлекает данные из медленного источника и вообще не хранит структуру?
Конечно. Но это уже другой случай, когда структуры данных не позволяют применить более эффективный алгоритм. Проблема же с предложенными тобой абстракциями, что они сами ограничивают эффективность выбираемых алгоритмов. В случае столь порицаемых тобой итераторов STL этого не происходит. Напротив, они вполне помогают в этом деле...
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
VladD2,
> ПК>Классная вышла "оптимизация". Например, в случае LinkedList мы получим совершенно избыточное копирование в массив только для того, чтоб пройтись по нему в обратном порядке.
> Если это станет узким метсом, то не долго написать специализацию и для него: >
Восхитительно! Какой общий подход. Осталось всего лишь добавить в эту функцию каждый из контейнеров, используемых пользователем.
Тем не менее, оставим восторги и вернемся к исходной задаче. Интересно, как будет называться поддиапазон связного списка в данной функции? В самом деле, LinkedList, очевидно, не подойдет... Соответственно, даже с добавлением такого явного "хэка", проблема с эффективностью обращения прохода по подпоследовательности (связного) списка, о чем так давно говорили большевики , при выбранном подходе так и осталась нерешенной.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, jazzer, Вы писали:
VD>>>Ни однин последовательный алгоритм принципиально не может перебирать ничего в обратном порядке без копирования в промежуточный массив.
J>>Ты не прав. В STL из любого двунаправленного (и его потомков) итератора можно получить итератор, дающий обход в обратном порядке.
VD>Без возможности переместиться в конец ты будешь перебирать элементы, что приведет к замедлению работы алгоритма.
Причем тут возможность переместиться в конец???
J>>Причем, опять же, ты можешь абстрагироваться от направления текущего итератора. J>>Т.е. если у тебя на входе итератор, который на самом деле осуществляет обратный обход, ты, обращая его, получаешь прямой, и тебе даже не нужно думать, что же у тебя во что превращается: ты можешь быть уверенным, что в результате ты получишь итератор с противоположным направлением обхода.
VD>Здорово. И получаем не универсальное решение так как однонаправленный итератор или будет крайне не эффективно разворачиваться, или вообще нельзя будет развернуть.
однонаправленный итератор в принципе нельзя эффективно развернуть, независимо от языка и библиотеки.
VD>В итоге мы начинаем зависеть от реализации контейнера, что есть нарушение условий паттерна "итератор".
Ничего подобного.
В STL мы всегда можем узнать у итератора, к какому классу итераторов он принадлежит, и, в зависимости от класса итератора, написать оптимизированные версии алгоритмов. Например, для двунаправленных и производных от них, типа итератора произвольного доступа, мы можем просто разворачивать итераторы, для однонаправленных итераторов — действовать через тот же промежуточный массив.
И контейнер с его реализацией нам тут абсолютно побоку, мы работаем только с итераторами.
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, vdimas, Вы писали:
V>>Нет, ну это уже несерьезно . Сам-то дочитал хотя бы до середины?
VD>Читал. V>>
V>>l Implementation Issues:
V>>= Who controls the iteration?
V>> — The client => more flexible; called an external iterator
V>> — The iterator itself => called an internal iterator
V>>= Who defines the traversal algorithm?
V>> — The iterator => more common; easier to have variant traversal techniques
V>> — The aggregate => iterator only keeps state of the iteration
V>>= Can the aggregate be modified while a traversal is ongoing? An iterator
V>>that allows insertion and deletions without affecting the traversal and
V>>without making a copy of the aggregate is called a robust iterator.
V>>= Should we enhance the Iterator interface with additional operations, such as
V>>previous()?
V>>Мне больше нечего добавить, считаем тему закрытой.
VD>И что ты тут такого обнаружил? Я где-то заявлял о том, что итераторы должны быть доступны только на чтение? Я гворил, о том, что они должны служить для перебора элементов, и не имеют права предоставлять прямого доступа. Иначе это уже не итераторы.
Да и я не утверждал, что итератор должен обладать качеством прямого доступа. Кстати, а не трудно тебе сформулировать, что ты называешь прямым доступом применительно к итератору? Может вообще весь этот спор ни о чем...
------
может тебе не нравится advance(), дык в итераторах листов она сымплементирована как ++ в цикле, прям "настоящие" тобой любимыые итераторы
вся эта байда с advance() из-за того, что алгоритмы выполнены как внешние сущности по отношению к контейнерам (причины ты сам знаешь), некоторые алгоритмы требуют "бытрого перебора" вперед или назад. Разработчик STL вполне естественно решил инкапсулировать в сам итератор ф-ию приращения на определенное число шагов, будучи уверенным, что во многих случаях это даст существенный выигрыш. Я не верю, что если бы эти алгоритмы разрабатывал ты, то не додумался бы до этого. Сделал бы так же, никуда бы не делся.
Как альтернативный вариант — все алгоритмы инкапсулированы в сами коллекции. Этот вариант даже обсуждать неохота, ибо программист С++ себе нормальную жизнь не представляет без алгоритмов, и "натравливает" он их куда ни попадя.
-------
все-таки нехватает мне в C# лаконичности функторов и просто глобальных ф-ий, одних только компареров уже тонна, а необходимость копировать коллекцию в массив перед сортировкой меня просто умиляет. Как выход — можно пытаться кастить ICollection к массиву или к ArrayList, а потом может еще к чему-либо, и так в каждом месте (а этих мест много) где мне просто требуется отсортировать коллекцию, полученную как результат.
Ну, как я есть автор приведенного поста, позволю себе высказаться.
Код — в чистом виде учебный, негоже его использовать как аргумент.
Если почитаешь ту ветку, найдешь такое решение (практическое), выполняющее ту же задачу:
Здравствуйте, VladD2, Вы писали:
VD>>>Глупость. Паттерн — это не задача. Это решение часто встречающейся задачи.
V>>Именно глупость, или невнимательное чтение оппонента. Задача описания паттерна — это тоже задача. GoF поставили задачу донести суть повторно применимых приемов до IT-сообщества. Похоже, перестарались с лаконичностью. Кое-кто воспринял слишком буквально. Им стоило разбавить свою книжку примерами и реализациями паттернов с учетом различных специфик, тогда этой ветки могло и не быть.
VD>Ответь. Ты ее вообще то читал? Там примеров как грязи. Да и не нужно других считать тупее себя. Я с самого начала говорил, о том, что в первую очередь нужно думать головой. Если тебе не подходит перебор, то этот паттерн не для тебя. Ищи другой или придумывай выход сам. Но если подходит, то паттерн определеят четкое решение проблемы. И это его суть. Это строительный блок, а не тема для фантазий.
Угу, и это громкое высказывание на фоне того, что соседней ветке ты сам привел ссылку, где как раз был описан именно минимальный пример, а затем оставлен простор именно для тех самых фантазий, не поленюсь скопирую:
l Implementation Issues:
= Who controls the iteration?
— The client => more flexible; called an external iterator
— The iterator itself => called an internal iterator
= Who defines the traversal algorithm?
— The iterator => more common; easier to have variant traversal techniques
— The aggregate => iterator only keeps state of the iteration
= Can the aggregate be modified while a traversal is ongoing? An iterator
that allows insertion and deletions without affecting the traversal and
without making a copy of the aggregate is called a robust iterator.
= Should we enhance the Iterator interface with additional operations, such as
previous()?
Вопросов оставлено больше, чем дано ответов в примере Так что, к чему столько эмоций?
Здесь предлагается, например:
— перебор в оба направления,
— модифицирование содержимого контейнера.
— далее, кто определяет способ навигации? Предлагается 2 варианта: сам контейнер или итератор. Если навигацией занимается сам контейнер, то вполне в духе инкапсуляции расширить итератор так же ф-ией MoveNextForNSteps(int N);
И т.д. и т.п. Заметь, что суть самого итератора, равно как и способ использования не поменялся — это просто перебор (только ли перебор? ) коллекции не имея представления об ее внешнем интерфейсе.
Я в упор не вижу противоречий ни с паттерном, ни с примерами, которых "как грязи" (т.е. с самыми простейшими обычно), ни тем более с тем, что сами разработчики подсказали первые же очевидные расширения и способы конкретных имплементаций паттерна ("фантазий" (С) Vlad2).
В общем, пока что продолжаю видеть зацикливание на "чистоте".
VD>>>Значит это не итераторы. Задача итератора — абстрагирование перебора элементов коллекции. Все!
Ну все — так все...
Я пока не вижу, чтобы мы вышли за рамки абстрагирования перебора (хотя предлагаются еще и модификации самой коллекции, ну да я не настаиваю). Ты абстрагировался, я абстрагировался, Степанов тоже абстрагировался, в общем все абстрагируются — паттерн работает.
V>>Опять проблема яйца и курицы. Итераторы в STL не цель, а средство. Собственно, как и везде.
VD>Какие яйца? Я СТЛ в глаза не видел, а итератор уже встречал.
Я спрашивал в контексте STL, из текста это понятно было всем. Nадцатый раз повторю, что требования к интерфейсам итераторов STL диктовались потребностями обобщенной работы алгоритмов. Тебе, вроде, должно быть известно, что любая разработка начинается со сбора требований.
V>>Попробуй по-другому.
VD>Зачем мне пробовать? Я делвают.
Да ну? Сделай нечто вроде remove_if на донете на итераторах. А теперь посмотри на то, что сделал (ибо только созданием копии), и преставь, что это кеш на десятки тысяч объектов, таких кешей довольно много, и у них подобная операция вызывается постоянно. (у системы потенциально тысячи одновременных сессий с клиентами, это не "текстовый редактор") Рискнул бы ты, как разработчик сделать, это "красиво" на итераторах?... даже на современной дешевой памяти? Вот и приходится подобную хрень БЕЗ итераторов делать, "в лоб" и "некрасиво".
Я же тебе уже сказал самю суть вопроса, в STL у меня не стоит вопрос: "быть или не быть" — всегда быть и не париться. А в дотнет вопрос постоянно стоит. Там где не требуется оптимизация — пишем "красиво", где требуется — "с умом" (С)Vlad2. В том самом уме надо еще изначально прикидывать, где же она требуется, а где нет...
VD>Я не зацикливаюсь не на чем. Я говрою о простых, казалось бы вещах, о дурной терминологии и мосорности итераторов в СТЛ.
А может просто взять и собрать воедино, перечислить, не торопясь, по пунктам, что там и в каким именно итераторах лишнее, и как именно это лишнее перечеркивает/меняет суть паттерна. А то пока лишь болтовня и бодания...
Здравствуйте, IT, Вы писали:
V>>Мне как приходится писать первое. И хотя основная масса кода (зачастую "линейная", т.е. практически без циклов) содержится в прикладной части, эффективность системы в целом определяет все-таки background.
IT>Общая эффективность системы определяется общей архитектурой.
Насколько общей?
есть эффективность отдельных подсистем. На стороне GUI эффективность некритична, если же к серваку одновременно подключены тысячи клиентов (часть клиентов у нас — это не юзвери, а программы-агенты-автоматы), одним словом общая картинка получается нескучной, поневоле задумаешься над тем, чему в ВУЗе учили, несмотря на современные мощщща
IT>for или foreach, даже в background, не могут влиять на это кардинально. Если же они всё таки начинают влияют, то нужно поднимать вопрос о смене приоритетов.
Иногда могут влиять кардинально
Если мне итератор не позволяет изменять коллекцию, по которой "бежит", то обычно делают измененную копию этой коллекции. Все это хорошо, пока у нас немного данных и итераторы бегают нечасто. Если же не так, то делаем на for, потому как подобных кешей много, я уверен, что в общем случае они регулярно будут оставаться за бортом второго поколения GC. Для Hashtable и того хуже — сначала отдельно создаем список ключей (для удаления, например), а потом пробегая по этому списку ключей удаляем из hashtable... В общем, некоторая "ломка" из-за отсутствия нечто вроде STL имеется.
Здравствуйте, VladD2, Вы писали:
VD>Я тут недавно... раздобыв вторую бэту сразу же запустил свой проект который сейчас пишу (редактор кода для Януса и R#-па за место Синтилы) под ним. Было забавно, что мои ожидания оказались очень близкими к тому что показал профайлер. Хотя в паре мест я все же ошибся. Так я не обратил внимания на промежуточные динамические массивы создаваемые в узких местах, а оказалось, что они то используются очень нехило. Решение было просто как три копейки. Вместо того, чтобы создавать их каждый раз я просто вынес их в статические переменные или поля класса. Чтобы не было проблем с многопоточностью пометил статические поля атрибутом ThreadStatic: VD>
VD>[ThreadStatic]
VD>private static List<StyledRange> _ranges = new List<StyledRange>(16);
VD>[ThreadStatic]
VD>private static List<int> _ndxs = new List<int>(16);
VD>
VD>И все дела! Если бы я мог вот так же за просто решать проблемы на С++ глядишь я и не стал бы искать лучшей жизни.
__declspec(thread) спасёт отца русской демократии. Реализации TSS есть и в сторонних библиотеках, в том же ACE. Ну только с деструкторами сложности будут. Хотя... с большой вероятностью, на C++ этого просто не понадобится.
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Здравствуйте, VladD2, Вы писали:
VD>Здорово. И получаем не универсальное решение так как однонаправленный итератор или будет крайне не эффективно разворачиваться, или вообще нельзя будет развернуть.
VD>В итоге мы начинаем зависеть от реализации контейнера, что есть нарушение условий паттерна "итератор".
Никакого нарушения паттерна в данном случае нет, поскольку:
1) Об эффективности перебора речи в описании паттерна не идёт;
2) Нельзя "разворачивать" однонаправленный итератор, т.е., в данном случае алгоритм манипуляции итератором зависит от самого итератора, а не контейнера.
Ну а в остальном присоединяюсь к jazzer.
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Здравствуйте, vdimas, Вы писали:
V>Да и я не утверждал, что итератор должен обладать качеством прямого доступа.
А именно это и напрягает/путает больше всего.
V> Кстати, а не трудно тебе сформулировать, что ты называешь прямым доступом применительно к итератору? Может вообще весь этот спор ни о чем...
Ну, вот разные там "it + 2" и т.п.
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>Конечно. Но это уже другой случай, когда структуры данных не позволяют применить более эффективный алгоритм. Проблема же с предложенными тобой абстракциями, что они сами ограничивают эффективность выбираемых алгоритмов. В случае столь порицаемых тобой итераторов STL этого не происходит. Напротив, они вполне помогают в этом деле...
Да не особо то что-то ограничивается. Ты все о каких-то очень абстрактных вещах рассуждашь, а обычный код он пишется не абстрактно. Они пишится под конкретное проетное решение. А то в свою очередь создается под конкретный фрэймоврк.
Что касается итераторв из СТЛ, то они несомненно гибки. Но притензии то не к этому. Их проблемы в другом. И я это говрил много раз. Они сильно замусоривают код и используют никуда не годную терминологию сбивающую с толку.
Что же до гибкости... повторное использование кода — это хорошо. Но это не смоцель. Какая мне радость с того, что я могу повторно использовать алгоритмы если мне приходится писать кучу обязочного кода там где это и нафиг казалось бы не унжно?
Коллекция дотнета с его интерфейсами — это не просто эффективно реализованный класс. Это еще и компонет. Его можно использовать в вижуальном дизанере, передавать в другие модули, расширять наследованием и т.п. И это очень дорогого стоит.
Понятно что реализации дотнета тоже не идеальна. Я, например, пару раз сталкивался с тем, что хочетелось модифицировать вэшью-типы хранимые в коллекции. А вот развернуть итератор ни разу хотелось (это к слову о теоретике). Однако со временем начал понимать, что нефига пихать в коллекции вэлью-типы. Но не рассчитаны они на них. Они проектировались под хранение ссылочных объектов. И как только перестаешь плыть против течения, то все становится просто и красиво.
Как я уже говорил, тройка IEnumerable<T>, ICollection<T> и IList<T> позволяют решать большинство задачь. Причем решения получаются очень простыми в понимании и достаточно эффективными. Отровенно говоря лично я IList<T> даже и не использовл то никогда. Ненужно как-то. Обычно алгоритмы которые попадаются под руку приходится применять или к массивам (а у них свой набор алгоритмов), или к List<T>. И нет не малейшего желания делать алгоритмы обобщенными. Они ведь решают конкретную задачу.
В общем, по жизи я получаю больше гибкости именно от простых решений, а не от супер-пупер наворотов.
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>Восхитительно! Какой общий подход. Осталось всего лишь добавить в эту функцию каждый из контейнеров, используемых пользователем.
Нет нужды. Все контейнеры уже учтены. Скажу боьше. LinkedList вообще нафиг не уперся. Я его прилепил уже в пылу теоритического спора.
ПК>Тем не менее, оставим восторги и вернемся к исходной задаче. Интересно, как будет называться поддиапазон связного списка в данной функции? В самом деле, LinkedList, очевидно, не подойдет... Соответственно, даже с добавлением такого явного "хэка", проблема с эффективностью обращения прохода по подпоследовательности (связного) списка, о чем так давно говорили большевики , при выбранном подходе так и осталась нерешенной.
Паш, проблем в том, что LinkedList в 99% задач вообще не нужен. Ну, не эффективен он. Особненно в дотнете где присвоение указателей стоит дороже чем в С++.
С диапазонами по энумераторам задача решается введением некого класса хранящего итератор и количество элементов. Однако опять же как-то не нужно оно на повреку. LinkedList по жизни не удачный выборк. А у IList нет проблемы пользоваться индексами. Возможно это не так гибко как если б ввести еще штук 5 промежуточных интерфейсов, но это просто и эффективно.
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.