2

i need help with storing group of (x, y) coordinates in a set. The way i store it is

set<int> s;
s.insert( (1, 1) );
s.insert( (1, 3) );
s.insert( (3, 1) );
s.insert( (3, 3) );

for (auto x: s) {
     cout << x << endl;
}

but it doesn't print out (1, 1), (1, 3).... and prints out instead 1, 3.

I am very new to c++, so would appreciate if anyone could give me advice on how to store these values with a set!

user3413646
  • 167
  • 2
  • 11

3 Answers3

5

What happens with you code is the following:

s is of type std::set<int> and therefore is suitable for storing variables of type int.

Calling the function std::set<int>::insert expects an argument of type int. If you do s.insert((1, 3)) you actually don't insert a pair but use the comma-operator. It works like this: In an expression a, b, expression a is evaluated, then expression b is evaluated and the result of expression b is returned as the result of the whole expression. You can read more about it here: How does the Comma Operator work.

Therefore s.insert((1, 3)) results in s.insert(3) and 3 is inserted into s.

To achieve the desired behaviour you can use std::pair, defined in the header utility. A possible way could be the following:

std::set<std::pair<int, int>> s;
s.insert(std::make_pair(1, 1));
s.insert(std::make_pair(1, 3));
s.insert(std::make_pair(3, 1));
s.insert(std::make_pair(3, 3));

for (const auto& e : s) 
  std::cout << "(" << e.first << ", " << e.second << ") ";

Output:

(1, 1) (1, 3) (3, 1) (3, 3)

An additional syntax to insert the pairs is the following using initializer lists:

s.insert({1, 3});

If you want to construct the pairs in place instead of constructing and inserting them, you can use std::set::emplace as follows:

s.emplace(1, 3);
dtell
  • 2,488
  • 1
  • 14
  • 29
1

i think you meant to use pairs,pair is a class couples together a pair of values which can be translated as coordinates x,y

set<std::pair<int,int>> s;

s.insert({ 1, 1 });
s.insert({ 1, 3 });
s.insert({ 3, 1 });
s.insert({ 3, 3 });

for (auto x : s) {
    std::cout << x.first<< " "<<x.second << std::endl;
}

// to print the first & the last element

    auto start = s.begin();
    auto last=s.rbegin();

    std::cout << start->first << " " << start->second << " " << last->first << " " << last->second<<'\n';

 // for the nth element
 int n=2;
 auto nelement=std::next(s.begin(), n);
 std::cout<<nelement->first<<" "<<nelement->second;
Spinkoo
  • 2,080
  • 1
  • 7
  • 23
  • May i also ask is it possible to print out only the first pair and the last pair of a set? – user3413646 Feb 02 '19 at 15:39
  • 1
    well its possible to iterate through it but it will be ordered( so not the exact same order they were in ) eg : input {2,1,5} if you iterate it will be {1,2,5} but the insert returns a reference to the inserted element so you can do something like this : in your first insert auto first = s.insert({1,1}); & same for the last insert – Spinkoo Feb 02 '19 at 16:04
  • i want it to be ordered so it is fine, but i just need to print out the first pair and last pair, is there a way to print the nth element? – user3413646 Feb 02 '19 at 16:06
  • 1
    check the ediit – Spinkoo Feb 02 '19 at 16:17
  • Thanks! but may i know what is rbegin()? why not end()? – user3413646 Feb 02 '19 at 16:26
  • set::end returns an iterator referring to the past-the-end element in the set container. The past-the-end element is the theoretical element that would follow the last element in the set container. It does not point to any element, and thus shall not be dereferenced. kind of like accessing an array of size n with a[n] but the last element is actually a[n-1] – Spinkoo Feb 02 '19 at 16:56
1

A set<int> can only store one int, not two (in a single insert operation). If you write s.insert( (1, 3) ); you are clearly trying to insert 2, and this can't work. It seems to work somehow, but actually the syntax is playing a nasty trick on you!

The expression (1, 3) in this case is using the comma operator, and what it does is: evaluate the 1 (it is, well, 1), throw it away, then evaluate the 3, which is clearly 3, and this is what is returned: 3. So your statement is actually equivalent to s.insert(3);. Taht's why you don't get a compilation error. But clearly this is not what you want.

To solve the problem you must use a set that stores two values at a time. There's a data type for that, called std::pair!

So you can declare it like

set<std::pair<int,int>> s;

and insert data into it like

s.insert({1, 3});
  • May i ask is it possible to only print out the first pair and last pair of the set? i read of using a iterator but can't get it to work – user3413646 Feb 02 '19 at 15:48
  • 2
    @user3413646 Yes, it is possible, but the oder might be different to the order of insertion. `std::set` uses a tree-like data structure to store its elements. Imagine a set containing ints that is constructed as follows: `std::set {5, 2 , -1, 2}` If you iterate over the set and print the elements, you will get `-1, 2, 5` instead of `5, 2, -1, 2`. If you need to preserve the order, another STL container is the better choice. See [this question](https://stackoverflow.com/questions/12863256/how-to-iterate-stdset) on how to iterate over a set. – dtell Feb 02 '19 at 15:52