Removal of repeated values

Asked

Viewed 259 times

5

I have two Vectors, each with coordinates (x,y). I need to reverse the second vector, getting with (y, x) and merging with the first, but I can’t get repeat in the first field, so I thought I’d use a set.

However, I need the second value of the structure to be as large as possible. For example, if I have the following values: {(3, 2); (3, 10)}, I need the pair to stay on the set (3,10).

It is possible to do this with set?

Example in pseudo-code:

vector<pair<int, int> > vector1 = {(10, 2); (10, 1); (3, 7)};
vector<pair<int, int> > vector2 = {(1, 3); (9, 10)};

Reversing the coordinates of the second vector would be with:

vector2 = {(3, 1); (10, 9)};

When mixing with the first vector, I want the values of the first field to be unique, while the values of the second are always the greatest. In case I wanted a set with the following values:

set1<pair<int, int> > set1 = {(10, 9); (3, 7)};
  • Your doubt is unclear. By vector and set you refer to std::vector and std::set? Can show an example of code?

  • 1

    Yes, William. I edited the post to try to explain the doubt better.

2 answers

5


Recital C++11, the following is valid:

vector<pair<int, int>> vec1 = {{10, 2}, {10, 1}, {3, 7}};
vector<pair<int, int>> vec2 = {{1, 3}, {9, 10}};

To invert the coordinates of each element of the second vector, you can do the following:

for (auto& coord : vec2)
    swap(coord.first, coord.second);

Now as to insert them into one std::set keeping only the highest value, you are probably doing something much wrong here. Checking if the value of the coordinate is already in the set will cost you a loop passing through all the elements of the set. This for each insert. So to insert n items, you need to operations. It’s a lot.

From what I understand you have a coordinate that identifies the pair and another that is only a value. Clearly you have a key pair and value and want to have a list of them without repeating keys. What you need is a std::map.

map<int, int> m;

void insertPair(const pair<int, int>& p) {
    if (m.find(p.first)) // Se já tem a key
        m[p.first] = max(m[p.first], p.second);
    else
        m[p.first] = p.second;
}

for (const auto& coord : vec1)
    insertPair(coord);

for (const auto& coord : vec2)
    insertPair(coord);

This function has complexity of n log(n) now that you don’t need to search all the elements for the key.

If you still want to use one std::set, has to go the long way:

set<pair<int, int>> s;

void insertPair(const pair<int, int>& p) {
    for (const pair<int, int>& p2 : s) { // percorra todo o set em busca do elemento
        if (p2.first == p.first) { // ao encontrar
            p2.second = max(p2.second, p.second); // troque o valor pelo maior
            return; // e retorne
        }
    }
    s.insert(p); // se não encontrou, basta inserir
}

for (const auto& coord : vec1)
    insertPair(coord);

for (const auto& coord : vec2)
    insertPair(coord);
  • Thank you, William. That was exactly the question. I will use a Std::map then.

3

Vector-only alternative solution (using Generic Both of c++14):

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

using namespace std;

int main() {
    vector<pair<int, int>> v1 = { {10, 2}, {10, 1}, {3, 7} };
    vector<pair<int, int>> v2 = { {1, 3}, {9, 10} };

    for(auto &p : v2)
        swap(p.first, p.second);
    v1.insert(end(v1), begin(v2), end(v2));
    sort(rbegin(v1), rend(v1));
    v1.erase(
        unique(begin(v1), end(v1),
            [](auto lhs, auto rhs) { return lhs.first == rhs.first; }),
        end(v1));

    for (auto &p : v1)
        cout << '(' << p.first << ", " << p.second << ')' << endl;
}

or:

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

using namespace std;

int main() {
    vector<pair<int, int>> v1 = { {10, 2}, {10, 1}, {3, 7} };
    vector<pair<int, int>> v2 = { {1, 3}, {9, 10} };

    for(auto &p : v2)
        swap(p.first, p.second);
    v1.insert(end(v1), begin(v2), end(v2));
    sort(rbegin(v1), rend(v1));
    vector<pair<int, int>> v3;
    unique_copy(begin(v1), end(v1), back_inserter(v3),
        [](auto lhs, auto rhs) { return lhs.first == rhs.first; });

    for (auto &p : v3)
        cout << '(' << p.first << ", " << p.second << ')' << endl;
}
  • pepper_chico, this solution does not guarantee that I will always have the highest value in the pair’s Second field for repeated keys, no?

  • @lfelix yes she guarantees, take a look at what happens when comparing greatness between two pairs. (2, 1) > (2, 0) > (1, 2) > (1, 1), etc. They make a lexicographical comparison.

  • @lfelix The balcony is, to make use of it and, to hit everything in the vector, to order, and then, to run the vector fishing paironly when the first mute. For example, doing this "fishing" in the list I gave earlier, take the first (2,1), the next is the same, the next is not, so fishing this, (1, 2), and the other is equal. In the end only (2, 1) and (1, 2) were fished.

  • @lfelix changed the code, I recommend a read earlier on Erase-remove idiom

  • 1

    I think you’d better use std::unique or std::unique_copy in this example of yours because it makes clearer what is happening and simplifies your code. Simply define a function or lambda that only compares the first element of the pairs passed to it. See an example: http://ideone.com/7Bvi3k

  • 1

    @Thiagogomes much better James, std::unique escaped me, and the use of std::transform for swap is cool too, I’ll integrate these tips, thanks.

Show 1 more comment

Browser other questions tagged

You are not signed in. Login or sign up in order to post.