0

I am trying to get union of 4 arrays using set_union. Here is the code I have so far:

int setA[5] = {2, 4, 5, 7, 8};
int setB[7] = {1, 2, 3, 4, 5, 6, 7};
int setC[5] = {2, 5, 8, 8, 15};
int setD[6] = {1, 4, 4, 6, 7, 12};

int AunionB[12];
int CunionD[11];
int finalUnion[23];

int *lastAunionB;
int *lastCunionD;

ostream_iterator<int> screen(cout, " ");

lastAunionB = set_union(setA, setA+5, setB, setB+7, AunionB);

cout << "AunionB = ";
copy(AunionB, lastAunionB, screen);
cout << endl;

lastCunionD = set_union(setC, setC+5, setD, setD+6, CunionD);

cout << "CunionD = ";
copy(CunionD, lastCunionD, screen);
cout << endl;

set_union(AunionB, AunionB+12, CunionD, CunionD+11, finalUnion);

cout << "Final Union = ";
copy(finalUnion, finalUnion+23, screen);
cout << endl;

When I ran the code, I got the following output:

AunionB = 1 2 3 4 5 6 7 8 
CunionD = 1 2 4 4 5 6 7 8 8 12 15 
Final Union = 1 2 3 4 5 6 7 2 4 4 5 6 7 8 8 12 15 52187240 1 1863041424 32767 0 0 

Therefore, the unions of setA and setB works as intended as does the union of setC and setD. However, when I try to get the union of all for sets, it doesn't work! I'm guessing the last 5 values of finalUnion are the address fields but how do I remove them? Also, the union itself is incorrect and I can't understand why.

Ankush
  • 6,767
  • 8
  • 30
  • 42
  • how is CunionD behaving as expected? In a true Union, no repeated elements are inserted in the final group. – gibertoni May 04 '15 at 18:15
  • @KuramaYoko No repeated elements are inserted if I used `vector` or `set`. However, I'm using arrays – Ankush May 04 '15 at 18:19
  • This is what I meant. How is this an expected behavior in your app. You shouldn't be using an Union operator then. It is misleading. – gibertoni May 04 '15 at 18:20
  • I believe that for `set_union` to work properly, the inputs must already match certain pre-conditions - i.e. they must be "sets" with no repeated elements. Your inputs `setC` and `setD` blatantly violate those preconditions, which results in `CunionD` not being correct, and thus being in violation of that precondition in the final union operation, which in turn results in an improper final answer. – twalberg May 04 '15 at 18:22

2 Answers2

1

A Union operation removes values that the two sets have in common.

Note that AUnionB has 8 elements (not the 12 that your code predicts).

You need to adjust your union-of-union code to account for the actual size of the two initial unions. You have everything prepared to do it correctly:

int *lastFinalUnion = set_union(AunionB, lastAunionB, CunionD, lastCunionD, finalUnion);

Note that set C has two distinct occurrences of 8 and set D has two distinct occurrences of 4, which is why they appear duplicated in the intermediate result.

UPDATE

Also, I tried your code and i'm getting the answer as 1 2 3 4 5 6 7 2 4 4 5 6 7 8 8 12 15 . Shouldn't the answer be 1 2 3 4 4 5 6 7 8 8 12 15

I believe you are correct, but I'm not in front of a C++ compiler to step through and see what's doing on, or to verify your output. The actual code was edited in by another SO member, but it looks correct to me.

In the simplest case, set_union performs the "union" operation from set theory: the output range contains a copy of every element that is contained in [first1, last1), [first2, last2), or both. The general case is more complicated, because the input ranges may contain duplicate elements. The generalization is that if a value appears m times in [first1, last1) and n times in [first2, last2) (where m or n may be zero), then it appears max(m,n) times in the output range.

https://www.sgi.com/tech/stl/set_union.html

Eric J.
  • 147,927
  • 63
  • 340
  • 553
  • I just took 12 as the max size of the union. How come when I printed `AunionB` no addresses were printed but they were printed in the case of the final union? Also, I tried your code and i'm getting the answer as `1 2 3 4 5 6 7 2 4 4 5 6 7 8 8 12 15` . Shouldn't the answer be `1 2 3 4 4 5 6 7 8 8 12 15` – Ankush May 04 '15 at 18:26
  • `I just took 12 as the max size of the union` The actual input union ends after 8 elements. The positions 9-12 from the actual end of the union to the position you specified are undefined (if C++ knew where the array ends, as e.g. C# does, it would not need you to specify the end position). That's also why set_union returns a pointer to the last position of the resulting union. – Eric J. May 04 '15 at 18:31
  • Ok. So I changed the array size but I'm still not getting the correct output! – Ankush May 04 '15 at 18:34
  • Visually inspecting the code I think you're right, but I don't have a C++ compiler in front of me at the moment. You might try leaving this question open for a bit to see if anyone can comment on that aspect, or you might try creating a new, simplified question that simply unions (1 2 3 4 5 6 7 8) with (1 2 4 4 5 6 7 8 8 12 15) and asks why 4 and 8 occur three times rather than the expected two. – Eric J. May 04 '15 at 18:40
1

The size of the AunionB and Cuniond is not 12 and 11 because:

Elements from the second range that have an equivalent element in the first range are not copied to the resulting range.

Try this code:

int setA[5] = { 2, 4, 5, 7, 8 };
int setB[7] = { 1, 2, 3, 4, 5, 6, 7 };
int setC[5] = { 2, 5, 8, 8, 15 };
int setD[6] = { 1, 4, 4, 6, 7, 12 };

int AunionB[12];
int CunionD[11];
int finalUnion[23];

int *lastAunionB;
int *lastCunionD;

ostream_iterator<int> screen(cout, " ");

lastAunionB = set_union(setA, setA + 5, setB, setB + 7, AunionB);

cout << "AunionB = ";
copy(AunionB, lastAunionB, screen);
cout << endl;

lastCunionD = set_union(setC, setC + 5, setD, setD + 6, CunionD);

cout << "CunionD = ";
copy(CunionD, lastCunionD, screen);
cout << endl;

int *finalUnionEnd;
finalUnionEnd = set_union(AunionB, lastAunionB, CunionD, lastCunionD, finalUnion);

cout << "Final Union = ";
copy(finalUnion, finalUnionEnd, screen);
cout << endl;

And then you got the right result:

Final Union = 1 2 3 4 4 5 6 7 8 8 12 15
AdamF
  • 2,501
  • 17
  • 30
  • I'm still getting the result as `1 2 3 4 5 6 7 2 4 4 5 6 7 8 8 12 15` – Ankush May 04 '15 at 18:22
  • @Ankush after 7 doy you really have 2 ? What compiler do you use ? You have 4 two times, because it is twice in setD. To remove it use std::unique algorithm on the final set or even better on setD and setC where 4 and 8 is twice. – AdamF May 04 '15 at 18:26
  • I added whole modified code. With replaced last lines. – AdamF May 04 '15 at 18:28
  • I'm fine with getting duplicates. The only thing I'm concerned with is that the union is not happening properly and the sorting is also not taking place – Ankush May 04 '15 at 18:33
  • Also, my compiler is gcc 4.2 – Ankush May 04 '15 at 18:37
  • I don't know how but I copied your code and pasted it and it works even though mine was the same! I guess i'll check again – Ankush May 04 '15 at 22:11