How to sort vector of struct C++ [duplicate] - c++

This question already has answers here:
Standard library sort and user defined types
(3 answers)
Closed 8 years ago.
I'm trying to sort vector of struct, but it ends with error. I tried to do it according to C++ reference, but I don't know where the problem is. Could someone help me?
#include <cstdlib>
#include <string>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
/*
*
*/
struct reg{
string name;
string addr;
};
int main(int argc, char** argv) {
vector <reg> a;
reg newReg = { "John", "Street1"};
a.push_back(newReg);
reg newReg2 = { "Mike", "Street2"};
a.push_back(newReg2);
std::sort (a.begin(), a.end());
return 0;
}

Unlike build-in types like int, float etc, you have to define the compare function for struct reg, i.e. rules that you want the elements to follow when sorting. Like this:
bool my_compare(const struct reg &x, const struct reg &y)
{
// define how to compare x,y here
}
And then, you can pass this function to sort the vector:
std::sort (a.begin(), a.end(), my_compare);

You either have to overload the comparison operator (less than, afair) or provide a custom comparison function.

You need to tell std::sort what makes one instance of the struct "less than" another instance of the struct.
In other words, if I give you two instances of those structs filled with data, and ask you "which one is placed before the other?", what is your answer? The rules you used to come with that answer is what you need to code and give to the 3 argument version of std::sort.

Related

using std::accumulate when there is pointer

Is this the only solution when there is a pointer that points to a vector and we would like to use accumulate to sum up numbers?
Is there any simpler solution rather than writing a lambda function and using a four argument type of accumulating?
Also, for using std::sort, will the situation be the same?
Here is the code:
#include <random>
#include <vector>
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
int main() {
const int N=3;
auto p=make_unique<array<int,N>> ();
(*p)[0]=3;
(*p)[1]=4;
(*p)[2]=5;
sum=accumulate(p,?,0);
return 0;
}
To answer your immediate question:
std::accumulate(p->begin(), p->end(), 0);
The same syntax will work for other STL algorithms as well.
Other improvements to your code snippet:
Avoid using #include<bits/stdc++.h>, see this post. Similarly for using namespace std, it's considered bad practise.
const N=3 -> const auto N=3
std::array is not a vector and you can initialise it directly using initializer-list syntax:
const auto* obj = new std::array<int,3>{3,4,5};

C++ creating a vector which stores different typenames

I want to create a vector which stores name of data types(int,char,bool,etc)
I am looking for something like:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main(int argc,char** argv)
{
vector<typenames> v = {int,float,double,bool};
}
If you have a finite set of types you want to store, you can use <variant>, e.g.
#include <variant>
using VarType = std::variant<int, float, double, bool>;
std::vector<VarType> v;
v.push_back(42);
assert(std::holds_alternative<int>(v.front()));
assert(std::get<int>(v.front()) == 42);
v[0] = true;
assert(std::holds_alternative<bool>(v.front()));
assert(std::get<bool>(v.front()));
Note that if C++17 is not available, you can go with Boost variant.
No. It's not possible. C++ is a statically-typed language, not a dynamic-typed language. What you can do is have set of enums, for types and put them into vector.
enum Type
{
IntType, FloatType, DoubleType, BoolType
};
vector<Type> v;
Or you can use std::variant (C++17).
Your question wasn't clear. Maybe you need std::pair or std::tuple to keep different items (with a defined number of elements).

Struct and arrays(C++) How to assign roll no to names using one array

I want to assign three roll numbers to three names but using only one array.. Please tell me how can i do that in c++. I think it is done using struct and arrays
You can make an array of std::pair. Prefer std::vector over raw arrays in c++, also highly prefer std::string over just an array of char.
#include <iostream>
#include <utility> //std::pair
#include <string>
#include <vector>
using namespace std;
int main()
{
//Raw array approach
pair<string, int> nameNumbersArr[3];
nameNumbersArr[0] = make_pair("Adam", 50);
nameNumbersArr[1] = make_pair("John", 30);
nameNumbersArr[2] = make_pair("David", 20);
//Vector approach
vector<pair<string, int>> nameNumbersVec;
nameNumbersVec.push_back(make_pair("Adam", 50));
nameNumbersVec.push_back(make_pair("John", 30));
nameNumbersVec.push_back(make_pair("David", 20));
return 0;
}
You can access the different parts of a pair using .first or .second
Example:
cout << nameNumbersVec[2].first << ' ' << nameNumbersVec[2].second << endl;
will print
David 20
It sounds like you're trying to make a map. In C++, std::map is a built-in, so something like this may be what you're looking for:
#include <map>
#include <string>
std::map<int, std::string> stdNames;
stdNames[10] = "Bob";
stdNames[23] = "John";
stdNames[50] = "Mary";
Now if you do not have access to built-ins, you can implement a mapping structure yourself. std::map is usually implemented as a red-black tree, though you can use an avl-tree or any other kind of self-balancing binary tree for the same purpose.
Now it sounds like you're fairly early in your degree, so you may not be comfortable implementing these yourself. In that case, you may want to create a Record struct, and have an array of those.
e.g. (typdefs/structs)
#define MAX_LEN 100
typedef struct {int rollNumber;
char name[MAX_LEN];} Record;
Record studentRecords[3];
Note that in this approach is really C not C++, and requires care around name lengths. Julian's answer shows you a C++ approach for this kind of result.
It really does sound like you need to read a couple of books from here though: The Definitive C++ Book Guide and List

Chaining non overlaping, non-contiguous iterators in c++ (/boost) [duplicate]

This question already has answers here:
Skip an entry of a random iterator
(2 answers)
Closed 8 years ago.
(Caveat: I'm a beginner in C++).
Consider this simple example:
#include <iostream>
#include <random>
#include <algorithm>
using namespace std;
template<class RandomAccessIterator1>
typename std::iterator_traits<RandomAccessIterator1>::value_type
foo(RandomAccessIterator1 firsta,RandomAccessIterator1 lasta,float store[]){
const float x1=*firsta;
int i=0;
for (RandomAccessIterator1 it=firsta;it!=lasta+1;it++){
store[i++]=x1-*it;
}
return(*(firsta+3));
}
int main(){
const int n=*nr;
int i;
float x[n],store[n];
for(i=0;i<n;i++) x[i]=(float)rand()/(float)RAND_MAX;
std::sort(x,x+n);
float a2=(x[1]+x[n-1])*0.5f;
int m0=std::upper_bound(x,x+n,a2)-x;
int m1=m0/2-1;
float var=foo(x,x+m0,store);
for(i=0;i<m0-1;i++) std::cout<< store[i] << std::endl;
}
My problem is that I need foo to not take x[m1] into account. Simply 'forget' that element as it were. But I don't really have access to the real foo itself: everything has to be done on the level of the inputs to foo, not the function itself. In other word, I need to somehow make firsta,lasta the bounds of
an RandomAccessIterator that contains all the elements in the range [firsta,lasta) except the m1-th. I don't have anything against using boost or other external
open source libraries. My only problem is that whatever solution should be O(1).
Oh, and I don't even know if it is possible.
I put the tag boost because there seems to be a series of related question on SO that solve this problem using boost.
If you can't do anything in foo that only really leaves you with the option of copying everything but the m1-th value into a vector (or some other random access container).
You could create a new iterator class that knows about values to skip. Something that looks roughly like this:
class MyIterator
{
public:
MyIterator(containerClass & myContainer, value_type valueToSkip);
private:
containerClass::iterator baseIterator;
value_type skipValue;
};
Obviously I've left out a lot of the details.

C++ sort method

I want to sort a vector using std::sort, but my sort method is a static method of a class, and I want to call std::sort outside it, but it seems to be trouble doing it this way.
On the class:
static int CompareIt(void *sol1, void *sol2) { ... }
std::sort call:
sort(distanceList.at(q).begin(),
distanceList.at(q).end(),
&DistanceNodeComparator::CompareIt);
Shouldn't it be possible to do this way?
std::sort takes a comparator that accepts value of the type held in the collection and returns bool. It should generally implement some notion of <. E.g., assuming your distanceList elements have collections of integers (I assume they don't, but for the sake of the example):
static bool CompareIt(int sol1, int sol2) { ... }
And of course you only need to supply a comparator if there isn't already a < operator that does the right thing for your scenario.
It should be a boolean method (sort uses operator <() by default to compare values)
The comparison function you've provided has the signature of the one needed by qsort, which is the sorting function that C provided before C++ came along. sort requires a completely different function.
For example if your declaration of distanceList is std::vector<DistanceNode> your function would look like:
static bool CompareIt(const DistanceNode &sol1, const DistanceNode &sol2)
{
return sol1.key < sol2.key;
}
Notice that sorting a std::list with the standard sort algorithm isn't efficient, which is why list supplies its own sort member function.
As others have mentioned, it needs a boolean return type. Here's an example which works:
#include "stdafx.h"
#include <vector>
#include <algorithm>
using namespace std;
class MyClass
{
public:
static bool CompareIt(const void *a1, const void *a2)
{
return a1 < a2;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
// Create a vector that contains elements of type MyData
vector<void*> myvector;
// Add data to the vector
myvector.push_back((void*)0x00000005);
myvector.push_back((void*)0x00000001);
// Sort the vector
std::sort(myvector.begin(), myvector.end(), MyClass::CompareIt);
// Display some results
for( int i = 0; i < myvector.size(); i++ )
{
printf("%d = 0x%08X\n", i, myvector[i] );
}
return 0;
}
[Edit] Updated the code above to make it a little simpler. I'm not suggesting it's nice code, but without know more about the OPs real implementation, it's difficult to give a better example!
First, the return type should be bool. Actually the requirement is only that the return type be assignable to bool, which int is. But the fact that you're returning int suggests that you might have written a three-way comparator instead of the strict weak ordering required by std::sort.
Your CompareIt function takes two void* pointers as parameters. Is distanceList.at(q) a vector<void*> (or vector of something convertible to void*)? If not, then the comparator inputs aren't right either. Using void* with algorithms also suggests that you're doing something wrong, because much of the point of generic programming is that you don't need opaque pointers that later get cast back to their original type.