fill structure while finding min_element, C++ - c++

I want to fill some structure while finding minimum element. Pl find the code below
tyoedef struct Point
{
double x, y;
}Point;
I have a vector of points - std::vector<Point> V in which i have few thousand points.
There is another struct I have
typedef struct cart
{
Point pt;
double val_1; // computed using only Pt
double val_2; // computer using only Pt
}cart;
Now I have two tasks:
I need to find minimum element from structure V.
Fill the structure cart, which is directly dependent on V.
I can do this using following code.
std::vector<cart> vCart;
for(unsigned i = 0; i < V.size(); ++i)
{
cart thsElement;
thsElement.pt = V[i];
thsElement.val_1 = compute_val_1(V[i]);
thsElement.val_2 = compute_val_2(V[i]);
vCart.push_back(thsElement)
}
auto it = std::min_element(vCart.begin(), vCart.end(), lex_sort);
bool lex_sort(cart const &a, cart const &b)
{
if(a.pt.x < b.pt.x) return true;
if(a.pt.x == b.pt.x) return (a.pt.y < b.pt.y);
}
Now there is an evident problem with this implementation.
There are two loops. One for filling the structure and other for finding the min element (std::min_element() has to have a loop to iterate over all the values). I am fighting for few miliseconds' improvement. So this is not a good code. Moreover, this seems so C_style
So I came up with following code.
std::vector<cart> vCart;
std::iterator <vCart> st_ite;
auto it = std::min_element(V.begin(), V.end(), boost::bind(FillStruct_LexSort, st_ite, _1, _2)); // V is a vector of Point
bool FillStruct_LexSort(std::insert_iterator< std::vector<Cart>> vcpInput, const Point &a, const Point &b)
{
Cart thsPt;
if(a.x() < b.x())
{
thsPt.pt = b;
thsPt.val_1 = compute_val_1(b);
thsPt.val_2 = compute_val_2(b);
(*vcpInput++) = (thsPt);
return true;
}
if (a.x() == b.x())
{
if(a.y() < b.y())
{
thsPt.pt = b;
thsPt.val_1 = compute_val_1(b);
thsPt.val_2 = compute_val_2(b);
(*vcpInput++) = (thsPt);
return true;
}
}
thsPt.pt = a;
thsPt.val_1 = compute_val_1(b);
thsPt.val_2 = compute_val_2(b);
(*vcpInput++) = (thsPt);
return false;
}
Now, the problem is - I get segmentation fault. I do not know how should I use iterator to insert a value. I tried passing reference to vCart, but vCart is empty after calling min_element(..). I even tried insert_iterator, but with no success.
So pl suggest.

It seems you want something like:
bool lex_sort(const Point& lhs, const Point& rhs)
{
return std::tie(lhs.x, lhs.y) < std::tie(rhs.x, rhs.y);
}
and then
auto it = std::min_element(V.begin(), V.end(), &lex_sort);
if (it == V.end()) {
// V is empty.
} else {
Cart thsPt;
thsPt.pt = it;
thsPt.val_1 = compute_val_1(*it);
thsPt.val_2 = compute_val_2(*it);
return thsPt;
}
Note that if val_1/val_2 always depend of pt, you can add a constructor for Cart which take a Point

Related

Unable to remove all object from vector

so basically i have a vector of objects called "Things" that I populate over the console. These are the name of the object I populate them with (tom, coin, coin, bomb).
for (int i = 0; i < 5; i++){
for (Thing * t : *locations[i]->getThings()) {
if (t->getName().compare("bomb") == 0){
for (Thing * all : *locations[i]->getThings()){
if(all->getName().compare("tom") != 0){
locations[i]->remove(all);
}
}
}
}
}
This code is run every time to check if there is a "thing" object called bomb in the list and would remove every other object other than tom.
So from the populated example above, the expected list should just be {tom}. However when the code runs it is {tom, coin} which means it fails to delete the other "non-tom" object
The problem is that you are modify the Things vector while you are still iterating through it, so you are going to be invalidating the iterators that the for loops are using, which is undefined behavior.
You can do something more like this instead, using the Erase-Remove idiom:
const auto is_bomb = [](const Thing *t){ return t->getName() == "bomb"; };
const auto is_not_tom = [](const Thing *t){ return t->getName() != "tom"; };
...
auto *things = locations[i]->getThings();
if (std::any_of(things->begin(), things->end(), is_bomb)){
things.erase(
std::remove_if(things->begin(), things->end(), is_not_tom),
things->end()
);
}
Or, if you are using C++20 or later:
const auto is_bomb = [](const Thing *t){ return t->getName() == "bomb"; };
const auto is_not_tom = [](const Thing *t){ return t->getName() != "tom"; };
...
auto *things = locations[i]->getThings();
if (std::any_of(things->begin(), things->end(), is_bomb)){
std::erase_if(*things, is_not_tom);
}

flip set of pixels with respect to a given row coordinate

I'm trying to write a program that flips a region(represented as a set of Segments) with respect to a given row coordinate.
I don't know c++ well, so I got some errors I don't know why they appeared and how to fixed them.
Here is what I got so far:
struct Segment
{
int row;
int colStart;
int colStop;
};
std::vector<Segment> FlipVertically(const std::vector<Segment>& region, const int flipRow){
std::vector<Segment> vec, more, less;
for (std::vector<Segment>::reverse_iterator it = region.rbegin(); it != region.rend(); ++it){
if ((*it).row > flipRow){
more.insert(more.begin(), *it);
}
else{less.insert(less.begin(), *it);}
};
std::sort(more.begin(), more.end(), [](Segment const &a, Segment const &b){
return a.row > b.row;
});
std::sort(less.begin(), less.end(), [](Segment const &a, Segment const &b){
return a.row > b.row;
});
vec.insert(vec.end(), more.begin(), more.end());
vec.insert(vec.end(), less.begin(), less.end());
int counter = 1;
int i = 0;
while(i + 1 < vec.size()){
if (vec[i].row == vec[i + 1].row){
vec[i].row = counter;
}
else{
vec[i].row = counter;
counter++;}
i++;
}
vec.back().row = counter;
return vec;
}
The function should return Segments stored from top to bottom row, and in the same row from left to right column.
It says there is an error in while loop: comparison between signed and unsigned integer expressions [-Wsign-compare].
Also, I'm looking for tips to improve my algorithm because I feel it is not good because of two sorts I do after dividing data. I was thinking if it is possible to iterate through region and place Segments in the order I want during first iteration but wasn't able to find a way to do it.
This line
for (std::vector<Segment>::reverse_iterator it = region.rbegin(); it != region.rend(); ++it){
needs to be changed to
for (std::vector<Segment>::const_reverse_iterator it = region.rbegin(); it != region.rend(); ++it){
since region is a const container. Thus calling begin/rbegin/end/rend on const containers will return const_...iterator_type... for these.
But, better yet, use auto to simplify.
for(auto it = region.rbegin(); it != region.rend(); ++it)
But the whole first loop can be modified to go faster by looping forward
for(auto const& value : region)
{
if(value.row > flipRow)
{
more.push_back(value);
}
else
{
less.push_back(value);
}
}
On a final note. The first part of you algorithm
std::vector<Segment> vec, more, less;
for (std::vector<Segment>::reverse_iterator it = region.rbegin(); it != region.rend(); ++it){
if ((*it).row > flipRow){
more.insert(more.begin(), *it);
}
else{less.insert(less.begin(), *it);}
};
std::sort(more.begin(), more.end(), [](Segment const &a, Segment const &b){
return a.row > b.row;
});
std::sort(less.begin(), less.end(), [](Segment const &a, Segment const &b){
return a.row > b.row;
});
vec.insert(vec.end(), more.begin(), more.end());
vec.insert(vec.end(), less.begin(), less.end());
can be condensed down to
auto vec = region;
std::sort(vec.begin(), vec.end(), [](Segment const& a, Segment const& b) {
return a.row > b.row;
});
This rendering the use of flipRow obsolete. If you think it is needed
then there is likely another flaw in the implementation.

Sorting a map of objects C++

I have a project where I have a game file which contains robots objects. The game file saves the robot objects using a map. The map contains the name of the robot as a key and the value is the robot object.
The robots are in 2D space, and they have x, y to find their current position.
One of the functions I have to implement is to sort the robots from smallest to largest by finding how far they are from the origin point (0, 0).
This is my map:
std::map<std::string, robot> robot_map;
I initialize the robot with a name and two variables to know the location and a third one to find the total amount of steps taken:
robot::robot(const string &n) : robot_name(n) { x = 0, y = 0, t = 0; }
And to check the robot distance from origin I use this:
std::string game::furthest() const
{
int furthest = 0;
std::string max_name;
typedef std::map<std::string, robot>::const_iterator iter;
for (iter p = robot_map.cbegin(); p != robot_map.cend(); ++p) {
if (distance(p->second) > furthest) {
furthest = distance(p->second);
max_name = p->first;
}
}
return max_name;
}
And this is the distance function:
int distance(const robot &r) {
int distance;
int y = r.north();
int x = r.east();
distance = abs(x - 0) + abs(y - 0);
return distance;
}
In my last function I would like to sort them in a vector, this is what I currently have:
std::vector<robot> game::robots_by_travelled() const
{
std::vector<robot> robots;
int furthest = 0;
typedef std::map<std::string, robot>::const_iterator iter;
for (iter p = robot_map.cbegin(); p != robot_map.cend(); ++p) {
robots.push_back(p->second);
}
return robots;
;
}
Is there a way to sort the vector by their distance from origin(0, 0)?
Yes, there is std::sort, which will sort on any appropriate relation:
std::sort(robots.begin(),
robots.end(),
[](const robot& lhs, const robot& rhs)
{ return distance(lhs) < distance(rhs); });
or, if you want a reusable predicate:
bool closer(const robot& r1, const robot& r2)
{
return distance(r1) < distance(r2);
}
// ...
std::sort(robots.begin(), robots.end(), closer);
You can also overload the < operator and just say
std::sort(robots.begin(), robots.end());
but that makes more sense when you have objects that can meaningfully be said to be "less than" each other and you want < in other situations as well.

Forming the maximum number out of the available numbers?

I am trying to solve the following question https://www.interviewbit.com/problems/largest-number/ : Given a list of non negative integers, arrange them such that they form the largest number.
For example:
Given [3, 30, 34, 5, 9], the largest formed number is 9534330.
Note: The result may be very large, so you need to return a string instead of an integer.
I have been able to solve it and implemented it, using comparison based sorting technique. That is, given two numbers X and Y, I compare two numbers XY (Y appended at the end of X) and YX (X appended at the end of Y). If XY is larger, then X should come before Y in output, else Y should come before. The following is the code:
string Solution::largestNumber(const vector<int> &A) {
// Do not write main() function.
// Do not read input, instead use the arguments to the function.
// Do not print the output, instead return values as specified
// Still have a doubt. Checkout www.interviewbit.com/pages/sample_codes/ for more details
vector<string> myvec;
for (int i = 0; i < A.size(); i++)
{
string s = to_string(A[i]);
myvec.push_back(s);
}
sort(myvec.begin(),myvec.end(),mycomp());
string s = "";
auto it = myvec.begin();
while (it != myvec.end())
{
string p = *it;
s = s + p;
it++;
}
return s;
}
struct mycomp
{
inline bool operator() (const string &p1, const string &p2)
{
string s1 = p1.append(p2);
string s2 = p2.append(p1);
if (s1.compare(s2) < 0)
return false;
else
return true;
}
};
But, the problem is, I have to merge the two functions into a single one because I just have to implement the single function. I cannot define one more function since I have no control over the entire piece of code (look at the link's submission part). Therefore, my ask is, how can I use the comparator by defining it inside the function string Solution::largestNumber(const vector<int> &A). Thanks!
This is a perfect place for a lambda.
sort(myvec.begin(), myvec.end(), [](const string &p1, const string &p2) {
string s1(p1 + p2);
string s2(p2 + p1);
return s1.compare(s2) >= 0;
});
I changed your code to not call append() on the strings, since you accept them as references to const objects, and p1.append(p2) tries to modify p1, but that's not allowed on a const object. Further, avoid constructs like if(x) return true else return false; and instead just return x;
Also, this
string s = "";
auto it = myvec.begin();
while (it != myvec.end())
{
string p = *it;
s = s + p;
it++;
}
return s;
Can be condensed to:
string s;
for (auto const& e : myvec)
s += e;
return s;
(Assuming you have a c++11 compiler or later)

Get all objects with a specific member value from a list of objects

From a vector
std::vector<S> structures;
containing structures of the type
struct S {
double x;
double y;
double weight;
};
I want to repeatedly get all the structs with a specific weight, i.e. I want to execute the following pseudocode:
do 1000 times:
weight = GetASpecificWeight()
MatchingStructures = structures.GetAllStructuresWithWeight(weight)
To do this efficiently, I want to sort the structuresvector and do a binary search in each iteration.
How can I implement this using std:: code?
Sorting the vector can be done using std::sort and finding the range of elements that have the specified weight can be done with std::equal_range.
However, as Daniel pointed out in the comment, it is likely that getASpecificWeight() returns a double and not a Structure, so in order to call equal_range we either need to create a dummy Structure or a function object that compares doubles to Structures with the desired semantics. A single lambda doesn't work because the binary search needs to be able to compare Structures to weights both ways.
Alternative 1: Using a dummy Structure
So first, lets create a dummy Structure, since this is less code.
In total, it might look something like this
auto sort_structure_by_weight_asc = [](Structure const& s1, Structure const& s2) {
return s1.weight < s2.weight;
};
std::sort(structures.begin(), structures.end(),
sort_structure_by_weight_asc);
for (auto i = 0; i < 1000; ++i) {
auto weight = GetASpecificWeight();
auto const dummy_structure = Strucutre{0.0, 0.0, weight};
auto range = std::equal_range(structures.cbegin(), structures.cend(),
dummy_structure, sort_structure_by_weight_asc);
if (range.first != structures.cend() && range.second != structures.cbegin()) {
// do whatever you want here
// if the `if`-condition isn't satisfied, no structure
// had weight `weight`.
}
}
If you need to modify the elements in the structures vector, you can replace cbegin and cend in the call to std::equal_range and the if-condition by begin/end respectively.
Alternative 2: Handcrafted function object
However, I personally don't think creating the dummy struct is very clean, so lets see how a custom function object would improve the code.
The function object itself can be defined as
struct ComparatorStructureToWeightAsc {
bool operator()(Structure const& s, double weight) const {
return s.weight < weight;
}
bool operator()(double weight, Structure const& s) const {
return weight < s.weight;
}
};
Then the code would look like this:
std::sort(structures.begin(), structures.end(),
[](auto const& s1, auto const& s2) { return s1.weight < s2.weight; });
for (auto i = 0; i < 1000; ++i) {
auto weight = GetASpecificWeight();
auto range = std::equal_range(structures.cbegin(), structures.cend(),
weight, ComparatorStructureToWeightAsc);
if (range.first != structures.cend() && range.second != structures.cbegin()) {
// do whatever you want here
// if the `if`-condition isn't satisfied, no structure
// had weight `weight`.
}
}
Alternative 3: Using Boost.Functional/OverloadedFunction
As you can see I'm bad at naming things, so having to name the function object used to compare Structures to weights is kind of awkward, in particular if it only used in this single place. If you have access to Boost, in particular to Boost.Functional/OverloadedFunction, you can use two lambdas instead of the handcrafted function object.
The code then looks like this:
std::sort(structures.begin(), structures.end(),
[](auto const& s1, auto const& s2) { return s1.weight < s2.weight; });
for (auto i = 0; i < 1000; ++i) {
auto weight = GetASpecificWeight();
auto range = std::equal_range(structures.cbegin(), structures.cend(), weight,
boost::make_overloaded_function(
[](Structure const& s, double weight) { return s.weight < weight; },
[](double weight, Structure const& s) { return weight < s.weight; }));
if (range.first != structures.cend() && range.second != structures.cbegin()) {
// do whatever you want here
// if the `if`-condition isn't satisfied, no structure
// had weight `weight`.
}
}