Find the first two consecutive pairs in the vector with greatest equal second

Pages: 12
Jun 22, 2021 at 3:38pm
One last question regarding vector of pairs. Suppose we have a vector of pairs like the following:

V { (1,10) (4,20) (3,50) (6,40) (8,50) (10,30) (7,40) (12,50) };

after sorting the vector with the sort algorithm based on the second of pairs we have:

V { (1,10) (4,20) (10,30) (6,40) (7,40) (3,50) (8,50) (12,50) };

Now, the question is, if we would like to find the first two consecutive pairs in the vector with greatest equal second, namely here pairs (3,50) and (8,50), any ideas on how we handle this?

Thanks
Last edited on Jun 22, 2021 at 3:38pm
Jun 22, 2021 at 4:28pm
Perhaps:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <vector>
#include <iostream>
#include <utility>
#include <algorithm>

using Pairs = std::pair<int, int>;

int main()
{
	const std::vector<Pairs> V { {1,10}, {4,20}, {10,30}, {6,40}, {7,40}, {3,50}, {8,50}, {12,50} };

	const auto greatest {V.back()};
	const auto first {std::partition_point(V.rbegin(), V.rend(), [&](const auto& v1) { return v1.second == greatest.second; }).base()};
	const auto sec {std::next(first)};

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

	if (sec != V.end())
		std::cout << sec->first << ' ' << sec->second << '\n';
}


which displays:


3 50
8 50

Jun 22, 2021 at 5:55pm
Seeplus thanks a lot. Today your help was extremely important! One last question regarding the above in conjuction with my previous thread. If instead of using the largest smallest, I choose to use this, the change will be something like this:

1
2
3
4
5
const auto greatest{ v.back() };
const auto first{ std::partition_point(v.rbegin(), v.rend(), [&](const auto& v1) { return v1.second == greatest.second; }).base() };
const auto sec{ std::next(prev) };
const auto K{ first - sec}; 
const double Div{ 1 / K.first };


Problem is that despite the fact that both now and before, I have two pairs (before largest and smallest) and (now prev and next), the code now does not compile as it considers K.first error. Any ideas why?
Last edited on Jun 23, 2021 at 3:01pm
Jun 23, 2021 at 9:05am
first/sec are iterators. So L10 should be:

 
const auto K {*first - *sec};

Jun 23, 2021 at 9:55am
Many thanks seeplus. I didn't notice they were Iterators. The compiler throws error for the line 3 after that:

Error C2676 binary '-': 'Pairs' does not define this operator or a conversion to a type acceptable to the predefined operator
Last edited on Jun 23, 2021 at 3:02pm
Jun 23, 2021 at 10:11am
You'll need to have the operator-() Pairs overload function from previous code.

1
2
3
Pairs operator-(const Pairs& p1, const Pairs& p2) {
	return {p1.first - p2.first, p1.second - p2.second};
}

Last edited on Jun 23, 2021 at 10:12am
Jun 23, 2021 at 10:13am
Well , that's the point! I have it and still throws that..
Jun 23, 2021 at 10:24am
This compiles ok:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <vector>
#include <iostream>
#include <utility>
#include <algorithm>

using Pairs = std::pair<int, int>;

Pairs operator-(const Pairs& p1, const Pairs& p2) {
	return {p1.first - p2.first, p1.second - p2.second};
}

int main()
{
	const std::vector<Pairs> V {{1,10}, {4,20}, {10,30}, {6,40}, {7,40}, {3,50}, {8,50}, {12,50}};

	const auto greatest {V.back()};
	const auto first {std::partition_point(V.rbegin(), V.rend(), [&](const auto& v1) { return v1.second == greatest.second; }).base()};
	const auto sec {std::next(first)};

	if (sec != V.end()) {
		const auto K {*first - *sec};
		const double Div {1.0 / K.first};
	}
}


Note the change to L22 to make the division double and not int.
Last edited on Jun 23, 2021 at 10:26am
Jun 23, 2021 at 10:43am
It throws a debug assertion failed runtime error

Expression:can't dereference out of range vector iterator

Jun 23, 2021 at 10:59am
My code above compiles OK as debug build and runs OK without any runtime errors as VS2019.

Adding this line after L22:

 
std::cout << Div << '\n';


displays:


-0.2


If your code is different from mine above, please post your code.


Jun 23, 2021 at 11:08am
The part of my code (altered to included the two greatest consecutive pairs instead of largsest - smallest) in which I needed help and discussed together in my posts so far is the following:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

  
            const string data {"data" }; 
            const string ex{ ".txt" };  
            const size_t lastFile{ 150 }; 
            map<string, double> mp;
            vector<Pairs> vec;
for (int i = 0; i <= lastFile; ++i) {
                stringstream ss;

                ss << data << setw(3) << setfill('0') << i << ex;

                ifstream fin(ss.str());

                if (!fin)
                    return (cout << "File open failed! " << ss.str() << '\n'), 1;

                Pairs p;
                fin >> p;
                vec.push_back(p);
                sort(vec.begin(), vec.end(), sortsec);
                const auto greatest{ vec.back() };
                const auto first{ std::partition_point(vec.rbegin(), vec.rend(), [&](const auto& V1) { return V1.second == greatest.second; }).base() };
                const auto sec{ std::next(first) };


               
                const auto K{ *sec - *first}; 
                const double Div{ 1.0 / K.first };	 


            }
}


Last edited on Jun 23, 2021 at 3:06pm
Jun 23, 2021 at 11:47am
Yep. It will! You haven't got my test for bad sec! What if v has only 1 entry - or several entries with different .second values? In these cases sec will be invalid.

See L20 of my code above.

PS. You do know you're only reading the first item from each file?
Last edited on Jun 23, 2021 at 11:52am
Jun 24, 2021 at 6:15am
Reasonable since I didn't wrote the sec != V.end() . I am much more inattentive than I should be.. Thanks you very much again seeplus.

PS. I sent you a pm.
Jun 24, 2021 at 10:31am
I am posting an enquiry regarding the code. I tried reading from files and store the data into a vector of pairs. However when I try to obtain the first two pairs with greatest second and then calculate K

1
2
3
4
5
const auto greatest {V.back()};
const auto first {std::partition_point(V.rbegin(), V.rend(), [&](const auto& v1) { return v1.second == greatest.second; }).base()};
const auto sec {std::next(first)};

if (sec != V.end()) const auto K {*first - *sec};


K always ends up being equal to zero. If some data in my file has a fractional part (i.e .5) I could understand that in case the pairs weren't of double type. Since I have define pairs as double, why do I get k equal to zero?
Last edited on Jun 24, 2021 at 11:30am
Jun 24, 2021 at 10:41am
What's the data?

You really need to get to grips with code debugging and the debugger. If K.first is 0 then you should be able to trace why back to the data - or to a code issue.
Last edited on Jun 24, 2021 at 10:47am
Jun 24, 2021 at 10:53am
I apologize. Data is from previously discussed code from 150 txt files to store it in a vector

Last edited on Jun 24, 2021 at 11:27am
Jun 24, 2021 at 11:01am
No. I meant what is the actual read data. What's in v?

PS. Have you got an int left somewhere that should be double?

If you know that the data type might change, then you could do something like:

1
2
3
4
5
6
//using T = int;
using T = double;

...

T val {};


In the code use T as type instead of int or double. That way to change the type used for data, it only needs changing in 1 place.
Jun 24, 2021 at 12:44pm
PPS I don't know what these numbers are - but if they're close to several decimal places, then subtraction could result in a number that 'seems' to be 0. Also you shouldn't compare double numbers for equality - you should compare that their absolute difference is < a specified value.

If a and b are double then for equality:

1
2
3
4
5
const double epsilon {0.000001};  // Or what is required

if (abs(a - b) < epsilon) {
  // a and b are consider equal here
}

Jun 25, 2021 at 7:03am
Many thanks Seeplus for everything!
Jun 25, 2021 at 7:51am
Boost Math Toolkit on comparing floating-point values to see if they are tolerably close enough to each other:

. Absolute difference/error: the absolute difference between two values a and b is simply fabs(a-b). This is the only meaningful comparison to make if we know that the result may have cancellation error.

. The edit distance between the two values: i.e. how many (binary) floating-point values are between two values a and b? ... probably only useful when you know that the distance should be very small.

. The relative distance/error between two values. This is quick and easy to compute, and is generally the method of choice when checking that your results are "tolerably close" to one another. However, it is not as exact as the edit distance when dealing with small differences...

https://www.boost.org/doc/libs/1_76_0/libs/math/doc/html/math_toolkit/float_comparison.html

Note: The relative distance/error between a and b is defined as fabs( (a-b) / min(a,b) )
Last edited on Jun 25, 2021 at 7:51am
Pages: 12