:)
Эксперт С++
4773 / 3267 / 497
Регистрация: 19.02.2013
Сообщений: 9,046
1

Что выбрать: пользовательский цикл или стандартный алгоритм с предикатом

24.07.2014, 15:45. Показов 1387. Ответов 20
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Всем привет.

Рассмотрим код (C++03, не C++11):
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <algorithm>
#include <iostream>
#include <iterator>
#include <list>
#include <map>
#include <string>
 
typedef std::pair<int, std::string> InputPair;
typedef std::map<int, std::string> InputContainer;
typedef std::list<std::string> OutputContainer;
 
void copyPart_Ver1( OutputContainer& oc, const InputContainer& ic )
{
    for( InputContainer::const_iterator it=ic.begin(); it!=ic.end(); ++it )
    {
        oc.push_back(it->second);
    }
}
 
struct TakeSecond
{
    std::string operator()( const InputPair& p ) const
    {
        return p.second;
    }
};
 
void copyPart_Ver2( OutputContainer& oc, const InputContainer& ic )
{
    std::transform(ic.begin(), ic.end(), std::back_inserter(oc), TakeSecond() );
}
 
int main() {
 
    InputContainer ic;
    
    ic[1] = "one";
    ic[2] = "two";
 
    std::ostream_iterator<std::string> oi( std::cout, " " );
 
    OutputContainer oc1;
    copyPart_Ver1( oc1, ic );
    std::copy( oc1.begin(), oc1.end(), oi );
    std::cout << std::endl;
    
    OutputContainer oc2;
    copyPart_Ver2( oc2, ic );
    std::copy( oc2.begin(), oc2.end(), oi );    
    std::cout << std::endl;
 
    return 0;
}
http://ideone.com/Gx8VoF



Задача: копирование части информации из одного контейнера в другой.

Самый очевидный и быстрый для написания вариант - это простой цикл (copyPart_Ver1).
Более сложный, но в то же время, использующий стандартный алгоритм, а значит должен быть
лучше понятен читающему код - copyPart_Ver2.

Требуется ваше мнение, какой вариант вы бы предпочли и почему? Или может быть есть другие варианты?

P.S. на C++11 я бы однозначно предпочел второй вариант, заменив конечно функциональный объект лямбдой.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
24.07.2014, 15:45
Ответы с готовыми решениями:

Алгоритм с применением вложенных базовых структур «цикл с предусловием» или «цикл с постусловием»
Разработать алгоритм с применением вложенных базовых структур «цикл с предусловием» или «цикл с...

Разработать алгоритм с применением вложенных базовых структур «цикл с предусловием» или «цикл с постусловием»
Разработать алгоритм с применением вложенных базовых структур «цикл с предусловием» или «цикл с...

Разработать алгоритм с применением вложенных базовых структур «цикл с предусловием» или «цикл с постусловием», составить
Разработать алгоритм с применением вложенных базовых структур «цикл с предусловием» или «цикл с...

Разработать алгоритм с применением вложенных базовых структур «цикл с предусловием» или «цикл с постусловием», составить
Разработать алгоритм с применением вложенных базовых структур «цикл с предусловием» или «цикл с...

20
Эксперт С++
3224 / 1751 / 436
Регистрация: 03.05.2010
Сообщений: 3,867
24.07.2014, 16:47 2
Ну, с современной точки зрения читаемость - самый важный критерий.
0
:)
Эксперт С++
4773 / 3267 / 497
Регистрация: 19.02.2013
Сообщений: 9,046
24.07.2014, 16:49  [ТС] 3
Mr.X, и какая читаемость читабельнее на Ваш взгляд (1 или 2)?
0
Эксперт С++
3224 / 1751 / 436
Регистрация: 03.05.2010
Сообщений: 3,867
24.07.2014, 16:56 4
Цитата Сообщение от Tulosba Посмотреть сообщение
Mr.X, и какая читаемость читабельнее на Ваш взгляд (1 или 2)?
Ну, ответ очевиден, по-моему. Алгоритм штука стандартная, и на него достаточно только бросить взгляд, а в цикле, написанном программистом, надо разбираться. Да и зачем писать циклы, если их за нас уже написал Степанов.
2
:)
Эксперт С++
4773 / 3267 / 497
Регистрация: 19.02.2013
Сообщений: 9,046
24.07.2014, 17:14  [ТС] 5
Цитата Сообщение от Mr.X Посмотреть сообщение
а в цикле, написанном программистом, надо разбираться.
Но ведь цикл однострочный (простой), а алгоритм требует функционального объекта (правда тоже простого, но всё же).
0
194 / 174 / 30
Регистрация: 10.07.2012
Сообщений: 800
24.07.2014, 17:25 6
мне кажется очень сомнительной идея скрывать под именем какого-то алгоритма то, что пишется в две очень легкие для восприятия строки. во-первых, я не могу угадать, что назвали словом "transform" - мне надо лезть смотреть, во-вторых, мне надо залезть посмотреть реализацию, ибо мало ли что. хотя если мне известно все содержимое <algorithm>, то мне может быть так же легко читать код со стандартными функциями.
0
В астрале
Эксперт С++
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
24.07.2014, 17:27 7
Цитата Сообщение от salam Посмотреть сообщение
во-первых, я не могу угадать, что назвали словом "transform" - мне надо лезть смотреть, во-вторых, мне надо залезть посмотреть реализацию, ибо мало ли что.
Значит вы не пишете на С++ и полезли смотреть исходник на С++, не изучая данный язык. В таком раскладе - да, нужно прочесть доку. Во всех остальных программист С++ знает что такое std::transform.

По теме: it depends. Предпочитаю алгоритмы, но чаще всего совсем не хочется хламить файл функторами на каждый чих, поэтому в основном все же for.
4
Эксперт С++
4985 / 3092 / 456
Регистрация: 10.11.2010
Сообщений: 11,169
Записей в блоге: 10
24.07.2014, 17:28 8
На мой взгляд первый вариант немного компактней и понятнее. Если у меня нет лямбды тогда я выберу его.
0
194 / 174 / 30
Регистрация: 10.07.2012
Сообщений: 800
24.07.2014, 17:33 9
Цитата Сообщение от ForEveR Посмотреть сообщение
Значит вы не пишете на С++ и полезли смотреть исходник на С++, не изучая данный язык. В таком раскладе - да, нужно прочесть доку. Во всех остальных программист С++ знает что такое std::transform.
тем не менее я пишу на С++ и не знал до сего момента что такое std::transform.
0
В астрале
Эксперт С++
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
24.07.2014, 17:34 10
salam, Что ж. Это странно. Пишете профессионально и прочитали хотя бы пару книг по С++? Я удивлен.
0
3257 / 2059 / 351
Регистрация: 24.11.2012
Сообщений: 4,909
24.07.2014, 18:22 11
В конкретно этом случае мне ближе обычный цикл.

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

Использование такого функтора будет оправданым если, например, в коде рядом сосредоночено несколько преобразований контейнеров и они уже написаны на стантанртных алгоритмах.
2
:)
Эксперт С++
4773 / 3267 / 497
Регистрация: 19.02.2013
Сообщений: 9,046
24.07.2014, 18:34  [ТС] 12
0x10, локальный функтор в c++03 нельзя передать в std::transform
1
710 / 283 / 16
Регистрация: 31.03.2013
Сообщений: 1,340
24.07.2014, 20:23 13
Очевидно, что стоит отдавать предпочтение более декларативному способу написания кода, а значит стандартным алгоритмам. Я сам предпочитаю следующие способы ( 1-ый самый предпочтительный, далее по убыванию )

1) если функтор достаточно простой ( как в примере топикстартера ), то использую bind
C++
1
std::transform( ic.cbegin(), ic.cend(), std::back_inserter( oc ), boost::bind( &InputPair::second, _1 ) );
2) лямбда
3) функциональную композицию при помощи boost::bind'а, но только в случае, если она не больше 2-3 строк
4) range-based loop
5) цикл

Добавлено через 8 минут
А, ну и если лямбды не завезли и с функциональной композицией тяжко - предпочитаю использовать свободные фукнции в качестве предикатов. Структурки с перегруженным operator() не нужны. Хранить состояние - зло
1
Ушел с форума
Эксперт С++
16473 / 7436 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
24.07.2014, 20:39 14
Цитата Сообщение от Tulosba Посмотреть сообщение
Самый очевидный и быстрый для написания вариант - это простой цикл (copyPart_Ver1).
Более сложный, но в то же время, использующий стандартный алгоритм, а значит должен быть
лучше понятен читающему код - copyPart_Ver2.
Однозначно первый вариант.
Он незамысловат и при этом выражен меньшим количеством строк.
0
Эксперт С++
1674 / 1046 / 174
Регистрация: 27.09.2009
Сообщений: 1,945
24.07.2014, 22:10 15
Цитата Сообщение от Voivoid Посмотреть сообщение
Очевидно, что стоит отдавать предпочтение более декларативному способу написания кода, а значит стандартным алгоритмам.
Сама эта мысль правильная, спора нет. Но вот в данном случае transform используется не по прямому назначению, ведь он предназначен для внесения изменений в исходный набор элементов, а не для их копирования. Так что вместо внесения ясности и декларации намерений использование этого алгоритма обманывает читающего и сбивает с толку. Раз уж нет возможности применить copy, лучше прибегнуть к явно написанному циклу.
1
Каратель
Эксперт С++
6609 / 4028 / 401
Регистрация: 26.03.2010
Сообщений: 9,273
Записей в блоге: 1
24.07.2014, 22:17 16
Цитата Сообщение от Nick Alte Посмотреть сообщение
Раз уж нет возможности применить copy, лучше прибегнуть к явно написанному циклу.
можно и написать свой back_inserter
0
:)
Эксперт С++
4773 / 3267 / 497
Регистрация: 19.02.2013
Сообщений: 9,046
24.07.2014, 22:18  [ТС] 17
Nick Alte, почему это transform для внесения в исходный набор? Там даже типы итераторов разные в шаблоне для входного и выходного диапазонов.
0
What a waste!
1608 / 1300 / 180
Регистрация: 21.04.2012
Сообщений: 2,729
24.07.2014, 22:23 18
Tulosba, можно взять boost и примерно так:
C++
1
boost::push_back(oc, ic | boost::adaptors::map_values);
0
Эксперт С++
1674 / 1046 / 174
Регистрация: 27.09.2009
Сообщений: 1,945
24.07.2014, 22:31 19
Цитата Сообщение от Tulosba Посмотреть сообщение
почему это transform для внесения в исходный набор?
Видимо, я не совсем удачно сформулировал. Смысл алгоритма - в применении некоторого преобразования к исходному набору данных. Сейчас, по некотором размышлении, я склоняюсь к мысли, что в описанном случае transform тоже может выражать замысел, если преобразованием считаем извлечение second. Хотя copy всё же кажется мне более подходящим по смыслу.
Так что основная моя мысль заключается в том, что для соблюдения принципов intentional programming надо учитывать предназначение алгоритмов. И как видим, иногда лучше не пожалеть нескольких минут на тщательное обдумывание вопроса.
0
710 / 283 / 16
Регистрация: 31.03.2013
Сообщений: 1,340
24.07.2014, 22:46 20
Цитата Сообщение от Nick Alte Посмотреть сообщение
ведь он предназначен для внесения изменений в исходный набор элементов
Если бы это было так, то не нужно было бы указывать output iterator
0
24.07.2014, 22:46
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
24.07.2014, 22:46
Помогаю со студенческими работами здесь

Преобразование типа из пользовательского в стандартный и из стандартного в пользовательский
Уважаемые форумчане, нужна ваша помощь в этом вопросе про преобразовния типов. Где об этом...

Передать в пользовательский элемент управления DataTemplate или что-то похожее
У меня есть UserControl, который получает список периодов и располагает их квадратиками на...

Что выбрать - Amd a8 3530mx или intel core i5 2450 или i7 2670qm?
Добрый день помогите выбрать процессор что мне лучше выбрать Amd a8 3530mx или intel core i5 2450...

Что выбрать на данный момент, что рекомендуете: Веб или Андроид?
Что рекомендуете, Андроид или Веб, какая сфера лучше(обе заходят), нравится и разаботка...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru