How to delete element of an array of structs? - c++

I have a program that has to choose between 10 bins of parts. Once the user have chosen a bin, the program ask if you want to either add or remove parts.my problem is when I am trying to add or remove from a single bin it adds and removes from all the bins.
struct Inventory
{
char description[35];
int num;
};
Inventory parts[Number_Bins] = {
{"Valve", 10},
{"Bearing", 5},
{"Bushing", 15},
{"Coupling", 21},
{"Flange", 7},
{"Gear", 5},
{"Gear Housing", 5},
{"Vacuum Gripper", 25},
{"Cable", 18},
{"Rod", 12}
};
This is my function to remove parts. I have another to add parts and it is similar. I could create like 10 of this for each element of the array but that is not the point.
void RemoveParts(Inventory bins[])
{
int e = 10;
int enter2;
cout << "Enter how many you want to remove\n";
cin >> enter2;
if (enter2 < 0)
{
cout << "Negative Values are not legal. Try again\n";
}
else
{
for (int index = 0; index < e; index++)
{
bins[index].num = bins[index].num - enter2;
}
}
}
I use a switch menu to pick up any bins. So there are 10 cases. Is there any way I can make it easier and write less code?

That's because you are looping through all the bins in here:
for (int index=0; index<e; index++){
bins[index].num = bins[index].num - enter2;
}
If you want to remove from a certain bin you have to tell your program which one.
From what I understand, you want to remove an entire bin...
To do this you have to remove the element from the array.
I suggest using either std::vector<Inventory> parts(Number_Bins) or std::array<Inventory, 10> parts; or even std::list<Inventory> parts(Number_Bins). then set up that.
Then removing elements will be just by using remove
To remove from your array specifically you have to shift the entire array.
//where enter2 is the element we want to erase
for (int index=enter2-1; index<total_size; index++){
bins[index] = bins[index + 1];
}
// then reinit content of last element
bins[total_size-1] = 0;
I don't recommend this road at all, it makes everything harder, and that feels like an understatement. This is why:
Now you have to check that setting the Inventory item to 0 successfully sets both variables to 0
Now you have to keep track of the number of Initialized elements in the array
You also need to track the size of the array
This is no C++, there is no encapsulation, no OOP, and this will likely force you to introduce global variables because you'll have to keep track of stuff.
Writing non scalable and non maintainable code is bad for your present, but most importantly, to your future.

Related

How to choose a random number excluding those which were previously chosen? [duplicate]

I'd like to make a number generator that does not repeat the number it has given out
already (C++).
All I know is:
int randomgenerator(){
int random;
srand(time(0));
random = rand()%11;
return(random);
} // Added this on edition
That function gives me redundant numbers.
I'm trying to create a questionnaire program that gives out 10 questions in a random order and I don't want any of the questions to reappear.
Does anyone know the syntax?
What I would do:
Generate a vector of length N and fill it with values 1,2,...N.
Use std::random_shuffle.
If you have say 30 elements and only want 10, use the first 10 out the vector.
EDIT: I have no idea how the questions are being stored, so.. :)
I am assuming the questions are being stored in a vector or somesuch with random access. Now I have generated 10 random numbers which don't repeat: 7, 4, 12, 17, 1, 13, 9, 2, 3, 10.
I would use those as indices for the vector of questions:
std::vector<std::string> questions;
//fill with questions
for(int i = 0; i < number_of_questions; i++)
{
send_question_and_get_answer(questions[i]);
}
You are trying to solve the problem "the wrong way".
Try this instead (supposing you have a vector<int> with question ids, but the same idea will work with whatever you have):
Get a random R from 0 to N-1 where N is the number of questions in the container
Add question R to another collection of "selected" questions
If the "selected questions" collection has enough items, you 're done
Remove question R from your original container (now N has decreased by 1)
Go to 1
Sounds like you essentially want to shuffle a deck of cards (in this case, the "cards" being the questions, or question numbers).
In C++, I would do:
#include <vector>
#include <algorithms>
std::vector<int> question_numbers;
for (unsigned int i = 0; i < 10; ++i)
question_numbers.push_back(i+1);
std::random_shuffle(question_numbers.begin(), question_numbers.end());
// now dole out the questions based on the shuffled numbers
You do not have to hand out all of the questions, any more than you have to deal out a whole deck of cards every time you play a game. You can, of course, but there's no such requirement.
Create a vector of 10 elements (numbers 1-10), then shuffle it, with std::random_shuffle. Then just iterate through it.
Should look more like this: (Note: does not solve your original problem).
int randomgenerator(){
int random;
// I know this looks re-dunand compared to %11
// But the bottom bits of rand() are less random than the top
// bits do you get a better distribution like this.
random = rand() / (RAND_MAX / 11);
return random;
}
int main()
{
// srand() goes here.
srand(time(0));
while(true)
{
std::cout << randomgenerator() << "\n";
}
}
A better way to solve the original problem is to pre-generate the numbers so you know that each number will appear only once. Then shuffle the order randomly.
int main()
{
int data[] = { 0,1,2,3,4,5,6,7,8,9,10,11};
int size = sizeof(data)/sizeof(data[0]);
std::random_shuffle(data, data + size);
for(int loop = 0; loop < size; ++loop)
{
std::cout << data[loop] << "\n";
}
}
Why not use some STL to perform the checks for you? The idea:
Create an (initially empty) set of 10 integers that will be the indices of the random questions (they will be distinct as a set forbids duplicate items). Keep pushing random numbers in [0, num_of_questions-1] in there until it grows to a size of 10 (duplicates will get rejected automatically). When you have that set ready, iterate over it and output the questions of the corresponding indexes:
std::vector<std::string> questions = /* I am assuming questions are stored in here */
std::set<int> random_indexes;
/* loop here until you get 10 distinct integers */
while (random_indexes.size() < 10) random_indexes.insert(rand() % questions.size());
for (auto index: random_indexes){
std::cout << questions[index] <<std::endl;
}
I may be missing something, but it seems to me the answers that use shuffling of either questions or indexes perform more computations or use an unnecessary memory overhead.
//non repeating random number generator
for (int derepeater = 0; derepeater < arraySize; derepeater++)
{
for (int j = 0; j < arraySize; j++)
{
for (int i = arraySize; i > 0; i--)
{
if (Compare[j] == Compare[i] && j != i)
{
Compare[j] = rand() % upperlimit + 1;
}
}
}
}

C++ How do I add an integer into a variable from a array using a another array

I know, the question is really complicated. Believe me, I am too. But I think a better programmer than me should know the solution. I have the following:
int cash[5] = {90000, 50000, 50000, 20000, 0};
int bankaccounts[3];
int dicenumberforeachplayer[3] = {6, 3, 9}; //Every indice is a player,
so dicenumberforeachplayer[0] is player one and so on
I have to add the highest cashnumber to the player, with the highest dicenumber, then the second player the second highest cash and so on. but I really don't know how. I am really confused, bc I am working on a project all day and I've come really far (i've written maybe 3000 lines of code) but I really hate to stop and confuse me with this problem for hours. Pls help me :((
I think, that I have to sort the player or sth like this and then I could use a for-loop for inserting the cash in every acc but I am really tired and I can't think right now XD
Modern C++ approach. There are no Magic numbers. Every thing is governed by the size of its respective array.
#include <algorithm>
#include <iostream>
int main()
{
int cash[5] = {90000, 50000, 50000, 20000, 0};
int bankaccounts[3] = {}; // added initializer to zero accounts
int dicenumberforeachplayer[3] = {6, 3, 9};
// iterate until we run out of prizes or players, whichever comes first
for (size_t cashcounter = 0;
cashcounter < std::min(std::size(dicenumberforeachplayer),
std::size(cash));
cashcounter++)
{
// find location in array of highest-rolling player
auto location = std::max_element(std::begin(dicenumberforeachplayer),
std::end(dicenumberforeachplayer));
// transform location into array index
auto index = std::distance(std::begin(dicenumberforeachplayer),
location);
//increase money in bank account for this player
bankaccounts[index] += cash[cashcounter];
// give winner impossibly low dice roll so they don't win again next time.
// Assumption: rolls cannot be negative. If they can, -1 might not be small enough
dicenumberforeachplayer[index] = -1;
}
// for display and test, print all accounts
for (const auto & val : bankaccounts)
{
std::cout << val << std::endl;
}
}
Use max_element to find the maximum and set the element to -1 then you can use the same max_element to get the next maximum element
int *max_player = max_element(dicenumberforeachplayer, dicenumberforeachplayer + 3);
int *max_money = max_element(cash, cash + 5);
bankaccount[(max_player - dicenumberforeachplayer)] += *max_money;
*max_player = *max_money = -1;

Searching using unordered map vs array

I have a block allocation function that takes in an array and then searches through it to find values 0 which indicates the free space, and then allocates blocks to the available free space. I am trying to use unordered map to improve the speed of searching for 0s. In my function, all the elements in the array are inserted into the unordered map. I was wondering if implementing unordered map like below even improves the searching speed compared to just using arrays?
int arr[] = {15, 11, 0, 0, 0, 27, 0, 0}; // example array
int n = sizeof(arr)/sizeof(arr[0]);
unordered_map<int, int> hash;
for(i=n;i>=0;i--)
{
hash[i+1] = arr[i];
}
for(auto v : hash)
{
if(v.second==0)
{
return v.second;
}
}
int arr[] = {15, 11, 0, 0, 0, 27, 0, 0};
int n = sizeof(arr)/sizeof(arr[0]);
for(i=0;i<n;i++)
{
if(arr[i]==0)
{
return arr[i];
}
}
First, note that both functions as you've written them always return zero, which is not what you want.
Now, to answer the main question: No, this approach doesn't help. In both cases you're just iterating over the values in the array until you hit on one that's a zero. This is an O(n) operation in the worst case, and introducing an unordered_map here is just slowing things down.
The most similar thing you could do here that would actually help would be something like
std::unordered_map<int, std::vector<int>> lookup;
for(int i = 0; i < n; i++)
{
lookup[arr[i]].push_back(i);
}
Now if you want to find a block with a zero in it you just an element from lookup[0].
However, given that we only need to track the blocks with zeroes in them, and not immediately look up the blocks with, say, a 13 in them, we may as well just do:
std::vector<int> emptyBlocks;
for(int i = 0; i < n; i++)
{
if(arr[i] == 0) { emptyBlocks.push_back(i); }
}
and then we can just grab empty blocks as we need them.
Note that you should take blocks from the back of emptyBlocks so that deleting them from the list doesn't require us to shift everything over. If you need to take the smallest indices first for some reason, traverse arr backwards when building the list of empty blocks.
That said, when you're allocating blocks typically you're trying to find a range of consecutive empty blocks. If that's the case, what you likely want is a way to look up the starting point of blocks of a given size. And you probably want it to be ordered, too, so that you can ask for "the smallest block at least this large."

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();
}

Need to find duplicates from an array in c++, and then put them in another array

this is my first post here and I would be very happy if you could help me.
The task is - Create an array from 6 input numbers, then put the duplicated numbers in another array and then output the array with the repeated numbers.
Do you have any ideas? I'm still a newbie and need some help. Thanks in advance guys !!
EDIT:
I'm not sure if I'm on the right way, that's why I didn't post what I've done yet. But this is it:
#include <iostream>
using namespace std;
int main()
{
int a[6];
int b[6];
int i,z;
for (i=0; i<6; i++){
cin>>a[i];
}
for (z=0; z<6; z++){
if (a[0]==a[1]) b[z]=a[0];
if (a[0]==a[2]) b[z]=a[0];
if (a[0]==a[3]) b[z]=a[0];
if (a[0]==a[4]) b[z]=a[0];
if (a[0]==a[5]) b[z]=a[0];
if (a[1]==a[2]) b[z]=a[1];
if (a[1]==a[3]) b[z]=a[1];
if (a[1]==a[4]) b[z]=a[1];
if (a[1]==a[5]) b[z]=a[1];
if (a[2]==a[3]) b[z]=a[2];
if (a[2]==a[4]) b[z]=a[2];
if (a[2]==a[5]) b[z]=a[2];
if (a[3]==a[4]) b[z]=a[3];
if (a[3]==a[5]) b[z]=a[3];
if (a[4]==a[5]) b[z]=a[4];
else b[z]=0; cout << b[z];
}
return 0;
}
To give you a better understanding of how to solve this, i'll try to show you what is going on via an example.
Lets say you have just entered the 6 numbers you request via cin, and your a[] variable now looks like this in memory:
a[] = { 5, 2, 6, 2, 1, 6 };
The duplicates here are 2 and the 6. (pretty obvious for us humans) :-)
You start to compare the first 2 values in memory: a[0]==a[1], then the first with the third: a[0]==a[2] and so on. If one of these match, you know the value of a[0] has at least one duplicate in memory.
Whenever that happens, you would like to do something that that information. Store it somewhere (like your b[] array) or just output it directly with cout << a[0].
You are now finished with checking a[0] and can continue with a[1] in the same manor, except you do not have to compare with a[0] because you did that in the previous step. Looking at your code, it seems you already understand that you can skip that.
Lets say you really need to store the duplicates. It would help to keep track of how many duplicates you have found.
Pseudo code:
duplicates = 0;
if (a[0] has a duplicate) { b[duplicates] = a[0]; duplicates++; }
if (a[1] has a duplicate) { b[duplicates] = a[1]; duplicates++; }
// etc...
"has a duplicate" would be like the code you had earlier, like: a[0]==a[1] || a[0]==a[2] || a[0]==[3] and so on.
In your example you have just 6 values, so it is not much work to write all the compare statements yourself. If you needed to do this with many more numbers, it would take you ages to write it, and is prone to little mistakes like typo's. Using a for loop would work for few and many numbers:
Pseude code:
duplicates = 0;
for (z = 0 to 6) {
for (y = z+1 to 6) {
if (a[z]==a[y]) {
b[duplicates] = a[z];
duplicates++;
break; // We know it is a duplicate, continue with the next value
}
}
}
But even this is not perfect. If one number occurs more than 2 times in memory, this will store the same duplicate value multiple times.