C++. Сборник рецептов - [106]

Шрифт
Интервал

или >back_inserter (как использовать >back_inserter, рассказывается в рецепте 7.5).

Объявление >set_union выглядит вот так.

>Out set_union(In first1, In last1, In first2, In last2, Out result);

Объявления >set_difference, >set_intersection и >set_symmetric_difference выглядят точно так же.

Чтобы использовать эти функции, сделайте так, как показано в примере 7.8. Например, чтобы найти пересечение двух множеств, вызовите >set_intersection вот так.

>set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(),

> inserter(setInter, setInter.begin()));

Последний аргумент >set_intersection требует некоторых пояснений, >inserter — это шаблон функции, определенный в >, который принимает контейнер и итератор и возвращает выходной итератор, который при записи в него значения вызывает для первого аргумента >inserter метод >insert. При его использовании для последовательного контейнера он вставляет значения перед >iterator, переданным в качестве второго аргумента. При его использовании для ассоциативного контейнера, как это делается в показанном выше фрагменте кода, этот итератор игнорируется, и элементы вставляются в соответствии с критерием сортировки контейнера.

>set — это удобный пример для наших целей, но операции над множествами работают для любых последовательностей, а не только для >set. Например, операции над множествами можно выполнить для >list:

>list lst1, lst2, lst3;

>// Заполняем их данными

>lst1.sort(); // Элементы должны быть отсортированы

>lst2.sort();

>set_symmetric_difference(lst1 begin(), lst1.end(),

>lst2.begin(), lst2.end(), back_inserter(lst3));

Однако так как >list хранит данные в неотсортированном виде, его вначале требуется отсортировать иначе результаты операций над множествами будут неверными. Также обратите внимание, что в этом примере вместо >inserter используется >back_inserter. >back_inserter работает аналогично >inserter, за исключением того, что для добавления элементов в контейнер он использует >push_back. Вы не обязаны действовать точно так же. Например, можно изменить размер выходного контейнера так, чтобы он стал достаточно большим

>lst3.resize(lst1.size() + lst2.size()),

>set_symmetric_difference(lst1.begin(), lst1.end(),

> lst2.begin(), lst2.end(), lst3.begin());

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

Если вы не знаете, что такое >set_symmetric_difference, я вам расскажу. Это объединение разностей двух множеств, определенных в прямом и обратном порядке. Это значит, что если а и b — это множества, то симметричная разность — это а - b b - а. Другими словами, симметричная разность — это множество всех элементов, которые присутствуют в одном из множеств, но отсутствуют в другом.

Есть еще один момент, который следует знать при работе с операциями над множествами. Так как последовательности не обязаны быть уникальными, можно получить «множество» с повторяющимися значениями. Конечно, строго математически множество не может содержать повторяющиеся значения, так что этот момент может быть не очевиден, Рассмотрим, как будет выглядеть вывод примера 7.8, если вместо >set использовать >list (при запуске примера 7.8 можно вводить повторяющиеся значения, но они не будут добавлены в >set, так как >set::insert не выполняется для элементов, которые уже присутствуют в >set).

>Введите несколько строк: a a a b с с

>^Z

>Введите еще несколько строк: a a b b с

>^Z

>Объединение a a a b b с с

>Различие: a c

>Пересечение: a a b с

Здесь операции над множествами перебирают обе последовательности и сравнивают соответствующие значения, определяя, что следует поместить в выходную последовательность.

Наконец, операции над множествами в их оригинальном виде (использующие для сравнения элементов >operator<) могут не работать так, как вам требуется, если последовательности содержат указатели. Чтобы обойти эту проблему, напишите функтор, который сравнивает объекты указателей, как в рецепте 7.4.

Смотри также

Рецепт 7.4.

7.9. Преобразование элементов последовательности

Проблема

Имеется последовательность элементов, и с каждым элементом требуется выполнить какие-либо действия — либо на месте, либо скопировав их в другую последовательность.

Решение

Используйте стандартные алгоритмы >transform или >for_each. Они оба просты, но позволяют выполнить почти любые действия с элементами последовательностей. Пример 7.9 показывает, как это делается.

Пример 7.9. Преобразование данных

>#include

>#include

>#include

>#include

>#include

>#include

>#include

>#include "utils.h" // Для printContainer(): см. 7.10


>using namespace std;


>// Преобразуем строки к верхнему регистру

>string strToUpper(const string& s) {

> string tmp;

> for (string::const_iterator p = s.begin(); p != s.end(); ++p)

>  tmp += toupper(*p);

> return(tmp);

>}


>string strAppend(const string& s1, const string& s2) {

> return(s1 + s2);

>}


>int main() {

> cout << "Введите несколько строк: ";

> istream_iterator start(cin);

> istream iterator end;

> list lst(start, end), out;

> // Используем преобразование с помощью унарной функции...


Рекомендуем почитать
Изучаем Java EE 7

Java Enterprise Edition (Java EE) остается одной из ведущих технологий и платформ на основе Java. Данная книга представляет собой логичное пошаговое руководство, в котором подробно описаны многие спецификации и эталонные реализации Java EE 7. Работа с ними продемонстрирована на практических примерах. В этом фундаментальном издании также используется новейшая версия инструмента GlassFish, предназначенного для развертывания и администрирования примеров кода. Книга написана ведущим специалистом по обработке запросов на спецификацию Java EE, членом наблюдательного совета организации Java Community Process (JCP)


Pro Git

Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.


Java 7

Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.


Создаем порт для FreeBSD своими руками. Часть II

Система сборки программ, используемая во FreeBSD, имеет значительно большие возможности, чем те, которые мы задействовали. Какие это возможности и как их использовать в своих портах?


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.


Как пасти котов. Наставление для программистов, руководящих другими программистами

«Как пасти котов» – это книга о лидерстве и руководстве, о том, как первое совмещать со вторым. Это, если хотите, словарь трудных случаев управления IT-проектами. Программист подобен кошке, которая гуляет сама по себе. Так уж исторически сложилось. Именно поэтому так непросто быть руководителем команды разработчиков. Даже если вы еще месяц назад были блестящим и дисциплинированным программистом и вдруг оказались в роли менеджера, вряд ли вы знаете, с чего надо начать, какой выбрать стиль руководства, как нанимать и увольнять сотрудников, проводить совещания, добиваться своевременного выполнения задач.