Sorting a map of objects C++ - 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.

Related

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.

Sort structure array in alphabetical order

I have a structure array (A[#]) named Sheep (since my task is about sheeps DNR). After I do whatever the task asked I am left with this struct :
struct Sheep
{
string Vardas;
char Fragmentas[CMax];
int atitikme = 0;
};
and inside my it the data is:
(string Vardas) | (char Fragmentas[CMax]) | (int atitikme)
Baltukas TAGCTT 3
Bailioji ATGCAA 3
Smarkuolis AATGAA 1
(char Fragmentas[CMax] won't be using so u don't have to look at it, I only named it to make it clear).
ALL of this data comes from U2.txt file and cant be manually typed in a code.
All its left to do is to sort it by these rules:
It goes from bigger to smaller by 'int atitikme'.
IF 'int atitikme' is equal then it will have to sort by 'A[#].Vardas in a in alphabetical order.
To sort it by 'int atitikme' I created a code:
string q;
char w[20];
int e;
for (int o = 0; o < n-1; o++)
{
for (int p = o+1; p < n-1; p++)
{
if (A[p].atitikme > A[o].atitikme)
{
// - Vardo Keitimas
q = A[o].Vardas;
A[o].Vardas = A[p].Vardas;
A[p].Vardas = q;
// - A[#].atitikme keitimas
e = A[o].atitikme;
A[o].atitikme = A[p].atitikme;
A[p].atitikme = e;
// - DNR farkmentu keitimas
for (int r = 0; r < m; r++)
{
w[r] = A[o].Fragmentas[r];
A[o].Fragmentas[r] = A[p].Fragmentas[r];
A[p].Fragmentas[r] = w[r];
}
}
}
}
n = 4 | m = 6
How/what do i need to add to this code to make it go:
else if (A[p].atitikme == A[o].atitikme)
{
<code>
}
That if 'atitikme' is == to another 'atitikme' then A[p].Vardas and A[o].Vardas has to be sorted in an alphabetical order. but only those 2 from the whole array.
OR if its too hard to understand what I meant, could anyone post a code, in the answer box, were it would sort in a alphabetical order between 2 string's?
NOTE:
the whole line data
(string Vardas) (char Fragmentas[CMax]) (int atitikme)
has to stay the same, only the place in the line has to be diffirent and sorted by those rules I mentioned before.
The output should be:
Bailioji 3
Baltukas 3
Smarkuolis 1
EDIT:
My current output is:
Baltukas 3
Bailioji 3
Smarkuolis 1
P.s. The task allows to use everything as-long as its C++ and does not have to create, or read, any other file.
Here I have used std::vector<> instead of array to store the sheeps.
Secondly, using std::sort() and a lambda function, you can easily mention how you want to sort the elements in the std::vector<>/ Sheeps. That would be the easiest way to approach.
Here is the live code, in case of reviewing: https://www.ideone.com/ay7TWU
#include <iostream>
#include <vector>
#include <algorithm>
struct Sheep
{
std::string Vardas;
std::vector<char> Fragmentas;
int atitikme;
};
int main()
{
std::vector<Sheep> vec =
{
{"Baltukas", {'T','A','G','C','T','T'}, 3},
{"Bailioji", {'A','T','G','C','A','A'}, 3},
{"Smarkuolis",{'A','A','T','G','A','A'}, 1},
{"Hmarkuolis",{'A','A','T','G','A','A'}, 1},
{"Kmarkuolis",{'A','A','T','G','A','A'}, 2}
};
std::sort(vec.begin(), vec.end(), [](const Sheep& lhs, const Sheep& rhs)
{
return (lhs.atitikme == rhs.atitikme) ?
lhs.Vardas < rhs.Vardas: // if atitikme's of sheeps are equal
lhs.atitikme > rhs.atitikme; // if atitikme's of sheeps are not equal
});
for (const auto& it: vec)
std::cout << it.Vardas << " " << it.atitikme << "\n";
return 0;
}
The output:
Bailioji 3
Baltukas 3
Kmarkuolis 2
Hmarkuolis 1
Smarkuolis 1
The best is to solve your problem one by one.
First - define the sorting order - see doc about - e.g. in std::less
So, you need functor class that defines your sorting order:
class SheepOrder
{
public:
bool operator() ( const Sheep& left, const Sheep& right) const
{
// It goes from bigger to smaller by 'int atitikme'.
if (left.atitikme > right.atitikme)
return true;
if (left.atitikme < right.atitikme)
return false;
//IF 'int atitikme' is equal then it will have to sort it in a in alphabetical order.
// I guess you meant Vardas
return left.Vardas < right.Vardas;
}
};
Now, having defined the order - just use std::sort - it can be used with arrays - no problem:
Sheep sheeps[100];
// ..
std::sort(std::begin(sheeps), std::end(sheeps), SheepOrder{});
or:
void sortSheeps(Sheep* array, std::size_t numOFSheeps)
{
std::sort(array, array + numOfSheeps, SheepOrder{});
}
You can also use std::tuple to make it easier to define sorting order (tuple has operator < by default if their elements have this operator too):
class SheepOrder
{
public:
bool operator() ( const Sheep& left, const Sheep& right) const
{
return tieMembersForSorting(left) < tieMembersForSorting(right);
}
private:
static auto tieMembersForSorting( const Sheep& object)
{
return std::make_tuple(-object.atitikme, // - to revert order
std::ref(object.Vardas)); // ref - to not make copy of string
}
};
With tieMembersForSorting defined as free function - lambda could be used as well (as it will be just one liner):
inline auto tieMembersForSorting( const Sheep& object)
{
return std::make_tuple(-object.atitikme, // - to revert order
std::ref(object.Vardas)); // ref - to not make copy of string
}
std::sort(begin(...), end(...), [](Sheep const& left, Sheep const& right)
{ return tieMembersForSorting(left) < tieMembersForSorting(right); });
https://en.cppreference.com/w/cpp/algorithm/sort shows you how to use std::sort.
You write a function bool less_than(const Sheep& a, const Sheep& b) that represents the order of two sheep and then simply call std::sort(container.begin(), container.end(), less_than);, with container being something like a vector of Sheep.
Edit: The function written out:
bool less_than(const Sheep& a, const Sheep& b)
{
if(a.atitikme != b.atitikme) return a.atitikme < b.atitikme;
return a.Vardas < b.Vardas;
}

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`.
}
}

fill structure while finding min_element, 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