Pairs & Tuples
Pairs
Introduction
Many times while solving various problem where we require 2 values to completely linked with each other in such a scenario it is best to use pairs.
Pair is a container that can be used to bind together a two values which may be of different types. Pair provides a way to store two heterogeneous objects as a single unit.
construction
The simplest form in general would be the following:
template<typename T1, typename T2> struct pair {
T1 first;
T2 second;
};
In general pair<int,int> is a pair of integer values. At a more complex level, pair<string, pair<int, int> > is a pair of string and two integers. In the second case, the usage may be like this:
pair<string, pair<int,int> > P;
string s = P.first; // extract string
int x = P.second.first; // extract first int
int y = P.second.second; // extract second int
We can also initialize a pair just like in vectors
pair <data_type1, data_type2> Pair_name (value1, value2) ;
pair <data_type1, data_type2> g1; //default
pair <data_type1, data_type2> g2(1, 'a'); //initialized, different data type
pair <data_type1, data_type2> g3(1, 10); //initialized, same data type
pair <data_type1, data_type2> g4(g3); //copy of g3
Functions
make_pair() | This template function allows to create a value pair without writing the types explicitly | O(1) |
operators(=, ==, !=, >=, <=) : | These operations can be appllied to pairs | O(1) |
swap() | This function swaps the contents of one pair object with the contents of another pair object. The pairs must be of same type. | O(1) |
Implementation
#include <iostream>
#include <utility> //required for pairs
using namespace std;
int main()
{
pair <int, char> PAIR1 ;
pair <string, double> PAIR2 ("Codecell", 1.23) ;
pair <string, double> PAIR3 ;
PAIR1.first = 100;
PAIR1.second = 'C' ;
PAIR3 = make_pair ("Codecell is Best",4.56);
cout << PAIR1.first << " " ;
cout << PAIR1.second << endl ;
cout << PAIR2.first << " " ;
cout << PAIR2.second << endl ;
cout << PAIR3.first << " " ;
cout << PAIR3.second << endl ;
pair<int, int>pair1 = make_pair(1, 12);
pair<int, int>pair2 = make_pair(9, 12);
cout << (pair1 == pair2) << endl; //compares both first and second values for equality
cout << (pair1 != pair2) << endl; // checks first if they are equal then second
cout << (pair1 >= pair2) << endl; //checks first followed by second
cout << (pair1 <= pair2) << endl;
cout << (pair1 > pair2) << endl;
cout << (pair1 < pair2) << endl;
cout << "Before swapping:\n " ;
cout << "Contents of pair1 = " << pair1.first << "," << pair1.second ;
cout << "Contents of pair2 = " << pair2.first << "," << pair2.second ;
pair1.swap(pair2);
cout << "\nAfter swapping:\n ";
cout << "Contents of pair1 = " << pair1.first << "," << pair1.second ;
cout << "Contents of pair2 = " << pair2.first << "," << pair2.second ;
return 0;
}
Output
100 C
Codecell 1.23
Codecell is Best 4.56
0
1
0
1
0
1
Before swapping:
Contents of pair1 = 1,12
Contents of pair2 = 9,12
After swapping:
Contents of pair1 = 9,12
Contents of pair2 = 1,12
Note
Pairs are mainly used at places where we need to rearrange certain data types(sort/insert) but keep together another value related to along with it throughout the process for certain use
By default sorting a pair related container causes data compared on the basis of first parameter although we can create some custom compare function to change the behavior
#include<bits/stdc++.h>
using namespace std;
int main()
{
// Declaring vector of pairs
vector< pair <int,int> > vect;
// Initializing 1st and 2nd element of
// pairs with array values
int arr[] = {10, 20, 5, 40 };
int arr1[] = {30, 60, 20, 50};
int n = sizeof(arr)/sizeof(arr[0]);
// Entering values in vector of pairs
for (int i=0; i<n; i++)
vect.push_back( make_pair(arr[i],arr1[i]) );
// Printing the original vector(before sort())
cout << "The vector before sort operation is:\n" ;
for (int i=0; i<n; i++)
{
// "first" and "second" are used to access
// 1st and 2nd element of pair respectively
cout << vect[i].first << " "
<< vect[i].second << endl;
}
// Using simple sort() function to sort
sort(vect.begin(), vect.end());
// Printing the sorted vector(after using sort())
cout << "The vector after sort operation is:\n" ;
for (int i=0; i<n; i++)
{
// "first" and "second" are used to access
// 1st and 2nd element of pair respectively
cout << vect[i].first << " "
<< vect[i].second << endl;
}
return 0;
}
Output:
The vector before applying sort operation is:
10 30
20 60
5 20
40 50
The vector after applying sort operation is:
5 20
10 30
20 60
40 50
Tuples
Introduction
Tuples are nothing completely different but pairs extended from their limitation of size two. In problem solving many time we may accross situation where we require 3-4 values linked together as one that is when we use tuples
A tuple is an object that can hold a number of elements. The elements can be of different data types. The elements of tuples are initialized as arguments in order in which they will be accessed
Operations
get() | get() is used to access the tuple values and modify them, it accepts the index and tuple name as arguments to access a particular tuple element |
make_tuple() | make_tuple() is used to assign tuple with values. The values passed should be in order with the values declared in tuple |
tuple_size | It returns the number of elements present in the tuple |
swap() | The swap(), swaps the elements of the two different tuples. |
tie() | The work of tie() is to unpack the tuple values into seperate variables. There are two variants of tie(), with and without “ignore” , the “ignore” ignores a particular tuple element and stops it from getting unpacked. |
tuple_cat() | This function concatenates two tuples and returns a new tuple |
Implementation
#include<iostream>
#include<tuple> // for tuple
using namespace std;
int main()
{
// Initializing variables for unpacking
int i_val;
char ch_val;
float f_val;
// Declaring tuple
tuple <char, int, float> gk;
// Assigning values to tuple using make_tuple()
gk = make_tuple('a', 10, 15.5);
// Initializing tuple
tuple <int,char,float> tup1(20,'g',17.5);
// Printing initial tuple values using get()
cout << "The initial values of tuple are : ";
cout << get<0>(gk) << " " << get<1>(gk);
cout << " " << get<2>(gk) << endl;
// Use of get() to change values of tuple
get<0>(gk) = 'b';
get<2>(gk) = 20.5;
// Printing modified tuple values
cout << "The modified values of tuple are : ";
cout << get<0>(gk) << " " << get<1>(gk);
cout << " " << get<2>(gk) << endl;
// Use of size to find tuple_size of tuple
cout << "The size of tuple is : ";
cout << tuple_size<decltype(gk)>::value << endl;
// Use of tie() without ignore
tie(i_val,ch_val,f_val) = tup1;
// Displaying unpacked tuple elements
// without ignore
cout << "The unpacked tuple values (without ignore) are : ";
cout << i_val << " " << ch_val << " " << f_val;
cout << endl;
// Use of tie() with ignore
// ignores char value
tie(i_val,ignore,f_val) = tup1;
// Displaying unpacked tuple elements
// with ignore
cout << "The unpacked tuple values (with ignore) are : ";
cout << i_val << " " << f_val;
cout << endl;
// Concatenating 2 tuples to return a new tuple
auto tup3 = tuple_cat(gk,tup1);
// Displaying new tuple elements
cout << "The new tuple elements in order are : ";
cout << get<0>(tup3) << " " << get<1>(tup3) << " ";
cout << get<2>(tup3) << " " << get<3>(tup3) << " ";
cout << get<4>(tup3) << " " << get<5>(tup3) << endl;
return 0;
}
Output:
The initial values of tuple are : a 10 15.5
The modified values of tuple are : b 10 20.5
The size of tuple is : 3
The unpacked tuple values (without ignore) are : 20 g 17.5
The unpacked tuple values (with ignore) are : 20 17.5
The new tuple elements in order are : b 10 20.5 20 g 17.5
Note
Although it might seem to you that tuples are not of much importance but that is not the case it does saves your time in and makes your code clean for writing nested pairs
Also the functionality of sorting of pairs can be extended to tuples by appropriately modifying the custom function involved.