creating a vector of objects - c++

I have just coded while on the train this, that creates a vector of objects.
I would appreciate if someone has a suggestion to make it more elegant or effective?
#include <iostream>
#include <vector>
using namespace std;
typedef struct{
short xpos,ypos;
short width, height;
short area;
}LABELPROP;
int get_property(int n,LABELPROP *pP)
{
if(n%2)
{
pP->xpos=n*2;
pP->ypos=n*3;
return 1;
}
else return 0;
}
int main()
{
vector<LABELPROP> myvector;
cout<<"Initial Number :"<<myvector.size()<<endl;
LABELPROP temporal;
// LABELPROP *pT=&temporal;
for(int n=1;n<=10;n++) //10 objects
{
//if(get_property(n,pT))
if(get_property(n,&temporal))
myvector.push_back(temporal);
}
for(int i=0;i<myvector.size();i++)
cout<<"("<<myvector[i].xpos<<","<<myvector[i].ypos<<")"<<endl;
return 0;
}
As you can see I eliminated an unnecessary pointer that I originally put.
the temporal struct gets its values from the get_property function so that is why I put that as a pointer
Thanks in advance

You are writing C++ in a C style. You don't need to typedef your struct, just use:
struct LabelProp
{
LabelProp(short xpos, short ypos) : xpos(xpos), ypos(ypos) {}
short xpos,ypos;
short width, height;
short area;
};
I also changed the naming, because most conventions use all uppercase names as constants or macros. I also added a constructor to be used.
You have get_property returning an int, but since this is c++, return a bool.
Probably an even better idea would be replace get_property with addIfOdd and have it look something like:
void addIfOdd(int n, std::vector<LabelProp>& results)
{
if(n%2)
{
results.emplace_back(n * 2, n * 3);
}
}
int main()
{
std::vector<LabelProp> myvector;
for(int n=1;n<=10;n++) //10 objects
{
addIfOdd(n, myvector);
}
}

It looks like you are unnecessarily iterating over a full range of integers when it is in fact the odd numbers that you're after. Why not limit the range to odd numbers? (only half as many iterations), e.g.:
for(int i = 1; i < 10; i += 2) { /* 1, 3, ..., 9 */ }
Using modern C++ you could add a constructor to your class:
explicit label_prop(int n)
: xpos{static_cast<short>(n * 2)}, ypos{static_cast<short>(n * 3)} {}
and replace all your code with a std::generate_n, e.g.:
std::generate_n(std::back_inserter(myvector), 5, [n = 1] () mutable {
return label_prop{std::exchange(n, n + 2)};
});
Here, you're specifying that you want 5 consecutive odd numbers, starting at 1.

If your compiler is modern enough and supports C++11 features, you could use the new range-based for loop, like this:
for(auto& x : myvector)
cout<<"("<<x.xpos<<","<<x.ypos<<")"<<endl;
Also, in order to improve the eficiency you can use the reserve method if you know in advance the size of the vector, so that you can avoid unnecessary object reallocations and memory allocations/deallocations, which can be expensive.

Related

Why this code works for 8 different test cases except 1 in C++?

So I wrote this function in C++ which basically counts the maximum number in an array and then prints out the number of maximum numbers in the array. Here's the code of the function:
int Number_of_maxNum(vector<int> ar) {
int max=0;
int Number_of_Maxnum=0;
int d = ar.size();
for(int i=0;i<=d;i++){
if(ar[i]>max){
max=ar[i];
}
}
for(int j=0;j<=d;j++){
if(ar[j]==max){
Number_of_Maxnum++;
}
}
return Number_of_Maxnum;
}
Now this code however doesn't work for the following array as input:
{44, 53, 31, 27, 77, 60, 66, 77, 26, 36}
It should print out 2, but print out 1
If someone could please explain what's actually going on with that input that's giving 1 as an input, It would
You have Undefined Behaviour. Arrays/vectors are indexed from 0 to Size-1. So change i<=d to i<d. This is most likely the reason for this strange result. Because you read your vector outside of its boundary, resulting in (effectively) random last value (note that this is UB, it can even crash your entire program).
Another thing is that you should initialize int max = std::numeric_limits<int>::min(); unless you guarantee that all elements of ar are nonnegative.
Finally you can do entire processing in a single loop. Try this:
int Number_of_maxNum(const vector<int>& ar) // <--- do this to avoid vector copy
{
int currentMax = std::numeric_limits<int>::min();
int counter = 0;
for (int value : ar) // <--- do this to avoid error prone manual indexing
{
if (value == currentMax)
{
counter++;
}
else if (value > currentMax)
{
currentMax = value;
counter = 1;
}
}
return counter;
}
The accepted answer is certainly correct, as well as explaining why your code is wrong.
However, you should also consider using the STL to do what you need, like this
int Number_of_maxNum(const std::vector<int>& ar)
{
if (ar.size() == 0)
return 0;
auto max = *std::max_element(ar.cbegin(), ar.cend());
return std::count(ar.cbegin(), ar.cend(), max);
}
Some of the advantages are:
It's easier to read (and write, once you're used to it).
There's no issues with off-by-one errors (as you had in your solution).
No worrying about initializing the maximum number to be the smallest possible number.
One disadvantage of this solution is that it loops over the vector twice. This can still be avoided by using the appropriate algorithm, e.g.
int Number_of_maxNum(const std::vector<int>& ar)
{
return std::accumulate(ar.cbegin(), ar.cend(), 0,
[max = std::numeric_limits<int>::min()]
(int count, int num) mutable {
return num > max ? max = num, 1 : count + (num == max);
});
}
This is effectively the conventional for-loop, so I'm not sure there's much to be gained by writing it this way. Also, mutable lambdas could be considered a code smell. You should use your judgement to decide which technique to use, once you are aware of the options.

Manipulating array's values in a certain way

So I was asked to write a function that changes array's values in a way that:
All of the values that are the smallest aren't changed
if, let's assume, the smallest number is 2 and there is no 3's and 4's then all 5's are changed for 3's etc.
for example, for an array = [2, 5, 7, 5] we would get [2, 3, 4, 3], which generalizes to getting a minimal value of an array which remains unchanged, and every other minimum (not including the first one) is changed depending on which minimum it is. On our example - 5 is the first minimum (besides 2), so it is 2 (first minimum) + 1 = 3, 7 is 2nd smallest after 2, so it is 2+2(as it is 2nd smallest).
I've come up with something like this:
int fillGaps(int arr[], size_t sz){
int min = *min_element(arr, arr+sz);
int w = 1;
for (int i = 0; i<sz; i++){
if (arr[i] == min) {continue;}
else{
int mini = *min_element(arr+i, arr+sz);
for (int j = 0; j<sz; j++){
if (arr[j] == mini){arr[j] = min+w;}
}
w++;}
}
return arr[sz-1];
}
However it works fine only for the 0th and 1st value, it doesnt affect any further items. Could anyone please help me with that?
I don't quite follow the logic of your function, so can't quite comment on that.
Here's how I interpret what needs to be done. Note that my example implementation is written to be as understandable as possible. There might be ways to make it faster.
Note that I'm also using an std::vector, to make things more readable and C++-like. You really shouldn't be passing raw pointers and sizes, that's super error prone. At the very least bundle them in a struct.
#include <algorithm>
#include <set>
#include <unordered_map>
#include <vector>
int fillGaps (std::vector<int> & data) {
// Make sure we don't have to worry about edge cases in the code below.
if (data.empty()) { return 0; }
/* The minimum number of times we need to loop over the data is two.
* First to check which values are in there, which lets us decide
* what each original value should be replaced with. Second to do the
* actual replacing.
*
* So let's trade some memory for speed and start by creating a lookup table.
* Each entry will map an existing value to its new value. Let's use the
* "define lambda and immediately invoke it" to make the scope of variables
* used to calculate all this as small as possible.
*/
auto const valueMapping = [&data] {
// Use an std::set so we get all unique values in sorted order.
std::set<int> values;
for (int e : data) { values.insert(e); }
std::unordered_map<int, int> result;
result.reserve(values.size());
// Map minimum value to itself, and increase replacement value by one for
// each subsequent value present in the data vector.
int replacement = *values.begin();
for (auto e : values) { result.emplace(e, replacement++); }
return result;
}();
// Now the actual algorithm is trivial: loop over the data and replace each
// element with its replacement value.
for (auto & e : data) { e = valueMapping.at(e); }
return data.back();
}

How can I generate a vector of vectors in a nice way?

I would like to have a function that has this definition:
vector<vector<int>> create_lists(int no_lists, int no_per_list)
The first argument is the number of sublist and the second argument is the number of items per sublist. Each list shall contain a subrange of a sequence of ints, so a call
create_lists(10,10);
will create 10 sublists, the first ranging from 0 to 9, second from 10 to 19 and so on.
I have done several versions of it, but they all feels clumsy. Is there a nice and elegant way to do this?
I rarely see an opportunity to say "use std::iota", so I'm not going to miss this one!
std::vector<std::vector<int>> create_lists(int no_lists, int no_per_list)
{
std::vector<std::vector<int>> v(no_lists,
std::vector<int>(no_per_list));
for (int i = 0; i < no_lists; ++i) {
std::iota(v[i].begin(), v[i].end(), no_per_list * i);
}
return v;
}
I would create the 2d vector with its default values as
std::vector<std::vector<int>> temp(no_lists, std::vector<int>(no_per_list));
Then I would iterate through each vector and transform them into the sequence values using
for (auto & e : temp)
std::transform(e.begin(), e.end(), e.begin(), [](int foo){static int counter = 0; return counter++;});
Putting it all together the function would be:
std::vector<std::vector<int>> create_lists(int no_lists, int no_per_list)
{
int counter = 0;
std::vector<std::vector<int>> temp(no_lists, std::vector<int>(no_per_list));
for (auto & e : temp)
std::generate(e.begin(), e.end(), [&counter](){return counter++;});
return temp;
}
And you can see it running in this Live Example
This may be the least exciting answer of them all, but I would probably simply use two for loops. This way seems least obscure and quickest to understand to me, which means the code is easier to understand later
std::vector<std::vector<int>> create_lists(int no_lists, int no_per_list)
{
std::vector<std::vector<int>> lol(no_lists, std::vector<int>(no_per_list));
int count = 0;
for(auto &list : lol)
for(auto &v : list)
{
v = count;
++count;
}
return lol;
}
This does one allocation and deallocation more than strictly necessary (the temporary vector<int> passed to the vector<vector<int>> constructor), but trying to avoid that would make the code slightly more complex and would probably not make much of a difference (your doing no_lists+1 allocations anyway).

Is a compile-time checked string-to-int map possible?

I'm probably trying to achieve the impossible, but StackExchange always surprises me, so please have a go at this:
I need to map a name to an integer. The names (about 2k) are unique. There will be no additions nor deletions to that list and the values won't change during runtime.
Implementing them as const int variables gives me compile-time checks for existence and type.
Also this is very clear and verbose in code. Errors are easily spotted.
Implementing them as std::map<std::string, int> gives me a lot of flexibility for building the names to look up with string manipulation. I may use this to give strings as parameters to functions which than can query the list for multiple values by appending pre-/suffixes to that string. I can also loop over several values by creating a numeral part of the key name from the loop variable.
Now my question is: is there a method to combine both advantages? The missing compile-time check (especially for key-existence) almost kills the second method for me. (Especially as std::map silently returns 0 if the key doesn't exist which creates hard to find bugs.) But the looping and pre-/suffix adding capabilities are so damn useful.
I would prefer a solution that doesn't use any additional libraries like boost, but please suggest them nevertheless as I might be able to re-implement them anyway.
An example on what I do with the map:
void init(std::map<std::string, int> &labels)
{
labels.insert(std::make_pair("Bob1" , 45 ));
labels.insert(std::make_pair("Bob2" , 8758 ));
labels.insert(std::make_pair("Bob3" , 436 ));
labels.insert(std::make_pair("Alice_first" , 9224 ));
labels.insert(std::make_pair("Alice_last" , 3510 ));
}
int main()
{
std::map<std::string, int> labels;
init(labels);
for (int i=1; i<=3; i++)
{
std::stringstream key;
key << "Bob" << i;
doSomething(labels[key.str()]);
}
checkName("Alice");
}
void checkName(std::string name)
{
std::stringstream key1,key2;
key1 << name << "_first";
key2 << name << "_last";
doFirstToLast(labels[key1.str()], labels[key2.str()]);
}
Another goal is that the code shown in the main() routine stays as easy and verbose as possible. (Needs to be understood by non-programmers.) The init() function will be code-generated by some tools. The doSomething(int) functions are fixed, but I can write wrapper functions around them. Helpers like checkName() can be more complicated, but need to be easily debuggable.
One way to implement your example is using an enum and token pasting, like this
enum {
Bob1 = 45,
Bob2 = 8758,
Bob3 = 436,
Alice_first = 9224,
Alice_last = 3510
};
#define LABEL( a, b ) ( a ## b )
int main()
{
doSomething( LABEL(Bob,1) );
doSomething( LABEL(Bob,2) );
doSomething( LABEL(Bob,3) );
}
void checkName()
{
doFirstToLast( LABEL(Alice,_first), LABEL(Alice,_last) );
}
Whether or not this is best depends on where the names come from.
If you need to support the for loop use-case, then consider
int bob[] = { 0, Bob1, Bob2, Bob3 }; // Values from the enum
int main()
{
for( int i = 1; i <= 3; i++ ) {
doSomething( bob[i] );
}
}
I'm not sure I understand all your requirements, but how about something like this, without using std::map.
I am assuming that you have three strings, "FIRST", "SECOND" and "THIRD" that you
want to map to 42, 17 and 37, respectively.
#include <stdio.h>
const int m_FIRST = 0;
const int m_SECOND = 1;
const int m_THIRD = 2;
const int map[] = {42, 17, 37};
#define LOOKUP(s) (map[m_ ## s])
int main ()
{
printf("%d\n", LOOKUP(FIRST));
printf("%d\n", LOOKUP(SECOND));
return 0;
}
The disadvantage is that you cannot use variable strings with LOOKUP. But now you can iterate over the values.
Maybe something like this (untested)?
struct Bob {
static constexpr int values[3] = { 45, 8758, 436 };
};
struct Alice {
struct first {
static const int value = 9224;
};
struct last {
static const int value = 3510;
};
};
template <typename NAME>
void checkName()
{
doFirstToLast(NAME::first::value, NAME::last::value);
}
...
constexpr int Bob::values[3]; // need a definition in exactly one TU
int main()
{
for (int i=1; i<=3; i++)
{
doSomething(Bob::values[i]);
}
checkName<Alice>();
}
Using enum you have both compile-time check and you can loop over it:
How can I iterate over an enum?

Two point crossover operation

I've been trying to write a code for two point crossover operation in a genetic algorithm. At first two random gene location is selected. After that, two chromosomes swap their genes which are located btw random numbers called genelocation1 and genelocatıon2.
for example First Gene [0.3,0.2,0.4,0,0.1,0.5,0.7]
Second Gene [0.25,0.6,0.45,0.15,0.80,0.9,0.85]
rndm genelocation1=3
rdnm gnelocation2 =5
child Gene1 [0.3,0.2,0.4,0.15,0.80,0.5,0.7]
Gene2 [0.25, 0.6, 0.45, 0, 0.1,0.9,0.85]
my problem is this: since two numbers are generated randomly, i could not define an array like array[genelocation2-genelocation1].. How can i solve the problem. here is my whole code about two point crossover. pointers maybe a solution but i am not good at pointers.
Here is the code:
void Xover (int mother,int father)
{
int tempo;
int Rndmgenelocation1=(rand()%ActivityNumber);
int Rndmgenelocation2=(rand()%ActivityNumber);
if (Rndmgenelocation1>Rndmgenelocation2)//sure that 2>1
{
tempo=Rndmgenelocation1;
Rndmgenelocation1=Rndmgenelocation2;
Rndmgenelocation2=tempo;
}
int size=(Rndmgenelocation2-Rndmgenelocation1);
int Temp1[size];//this makes an error
int ppp=Rndmgenelocation1;
for (int pp=Rndmgenelocation1;pp<Rndmgenelocation2;pp++)
{
Temp1[pp]=Sol_list[father].Chromosome[ppp];
ppp++;
}
int pppx=Rndmgenelocation1;
for (int ppx=Rndmgenelocation1;ppx<Rndmgenelocation2;ppx++)
{
Sol_list[father].Chromosome[ppx]=Sol_list[mother].Chromosome[pppx];
pppx++;
}
int ppplx=Rndmgenelocation1;
for (int pplx=Rndmgenelocation1;pplx<Rndmgenelocation2;pplx++)
{
Sol_list[father].Chromosome[pplx]=Temp1[ppplx];
ppplx++;
}
return;
}
You can't define an array of variable size on the stack.
You could use
int *Temp1=new int[size]
You then must not forget to call
delete[] Temp1;
at the end of your function!
edit:
I didn't test my code below, but the following should do what you want in a more efficient (and more understandable) way:
#include <algorithm>
void Xover (int mother,int father)
{
int Rndmgenelocation1=(rand()%ActivityNumber);
int Rndmgenelocation2=(rand()%ActivityNumber);
if (Rndmgenelocation1>Rndmgenelocation2)//sure that 2>1
{
std::swap(Rndmgenelocation1,Rndmgenelocation2);
}
for (int pp=Rndmgenelocation1;pp<Rndmgenelocation2;pp++)
{
std::swap(Sol_list[father].Chromosome[pp],Sol_list[mother].Chromosome[pp]);
}
return;
}
edit2:
I just found here another even better way - the STL implements a ready-to-use cross over algorithm. Use:
#include <algorithm>
void Xover (int mother,int father)
{
int Rndmgenelocation1=(rand()%ActivityNumber);
int Rndmgenelocation2=(rand()%ActivityNumber);
if (Rndmgenelocation1>Rndmgenelocation2)//sure that 2>1
{
std::swap(Rndmgenelocation1,Rndmgenelocation2);
}
std::swap_ranges(
Sol_list[father].Chromosome[Rndmgenelocation1],
Sol_list[father].Chromosome[Rndmgenelocation2],
Sol_list[mother].Chromosome[Rndmgenelocation1]
);
return;
}
I'm guessing you must not be using g++ as your compiler. If so, you can use a std::vector rather than an array. Simply do
std::vector<int> array(size);
Now you can treat it like a "normal" array though the operator[] syntax. There's also no concern about memory leaks from forgetting to call delete on a pointer.