Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

One liner for inserting some particular value of class object

Suppose I have a vector<int> myVec; and I want to convert it to a set, I can have a one liner-

set<int> mySet(myVec.begin(), myVec.end());

This is something that can be found easily.

Now I have vector<pair<int, int>>, and I want to obtain the set of the second values in each of the pairs. How should I use a set constructor to achieve this? Is it possible?

Assuming I have C++11, C++14, C++17.

Also, I would appreciate if I can get some information about how to do similar tweaks in a general sense for different containers.

like image 305
user3903448 Avatar asked Sep 25 '18 12:09

user3903448


3 Answers

Asking for one-liner in this case inevitably leads to a solution with range-v3:

#include <range/v3/view/map.hpp>

const std::vector<std::pair<int, int>> myVec{{1, 10}, {2, 20} , {3, 30}};
const std::set<int> mySet = myVec | ranges::view::values;

And a similar approach with Boost range¹:

#include <boost/range/adaptor/map.hpp>

using boost::adaptors::map_values;
const auto mySet = boost::copy_range<std::set<int>>(myVec | map_values); 

You might consider this approach the simplest, however (no libraries, but C++17 required):

for (const auto& [first, second] : myVec)
    mySet.insert(second);

¹ Thanks to @Caleth for suggesting an improvement in the comments.

like image 127
lubgr Avatar answered Nov 08 '22 13:11

lubgr


This almost-one-liner should work for you:

#include <algorithm>
#include <iterator>
#include <iostream>
#include <set>
#include <utility>
#include <vector>

int main()
{
    std::vector<std::pair<int, int>> myVec = { {1, 2}, {3, 4} };
    std::set<int> mySet;
    std::transform(myVec.begin(), myVec.end(), std::inserter(mySet, mySet.begin()),
                   [](const std::pair<int, int>& elem) { return elem.second; });
    for (int value : mySet)
    {
        std::cout << value << std::endl;
    }
    return 0;
}

Output:

2
4
like image 6
jdehesa Avatar answered Nov 08 '22 13:11

jdehesa


The most C++y way to do this is probably to define a custom iterator type which produces only the second value.

You can use very similar code as that for a more common query, which is to take the values from a map: iterator adapter to iterate just the values in a map?

Or, you know, just write a loop. Nothing wrong with that.

like image 5
John Zwinck Avatar answered Nov 08 '22 11:11

John Zwinck