I have an issue how to implement to compare two static arrays, ie.
string bufferNames[]={"apple","orange","banana","pomegranate","pear"};
string bufferPictures[] = {"apple.bmp","orange.bmp","banana.bmp","pomegranate.bmp","pear.bmp"};
Each item in the bufferNames presents the choice that to someone has been given, when the picture from the bufferPictures has been loaded onto the screen. So, if I for example get orange.bmp using rand() function that iterates through that list, how can I get the same one corresponding element orange and two other random not correct elements. Any help would be appreciated.
Thanks in advance.
P.S. If further breaking in of the problem is needed, just say it so.
This should do it. The code makes use of the C++11 features. You will
need to adapt it, to pass it off as homework.
#include <string>
#include <iostream>
#include <algorithm>
#include <vector>
struct Picture {
std::string name, file;
bool operator==(const Picture& x) const { return this->name == x.name && this->file == x.file; }
bool operator!=(const Picture& x) const { return !(*this == x); }
};
int main()
{
std::vector< Picture > pics =
{
{"apple", "apple.bmp"},
{"orange", "orange.bmp"},
{"banana", "banana.bmp"},
{"pear", "pear.bmp"},
};
// determined by random choice
const Picture& choice = pics[0];
std::vector< Picture > woChoice;
std::copy_if(pics.begin(), pics.end(), std::back_inserter(woChoice),
[&choice](const Picture& x) {
return x != choice;
});
// random shuffle the remainder and pick the first
// two. alternatively and for more efficience use std::random to
// generate indices
std::random_shuffle(woChoice.begin(), woChoice.end());
std::cout << woChoice[0].name << std::endl;
std::cout << woChoice[1].name << std::endl;
return 0;
}
So, if I for example get orange.bmp using rand() function that iterates through that list, how can I get the same one corresponding element orange and two other random not correct elements.
If you use rand() to get a number (let's call it x) between 0 and 4 inclusive (based on there being 5 distinct values in the arrays), then you can use that number in both arrays to find the related word and image.
To get one other random incorrect element, you can call rand() in a loop until you get a value other than x. Let's call it y.
To get another random incorrect elements, you can call rand() in a loop until you get a value other than x and y.
There are other ways to do this, but that's probably easiest to understand and implement.
The names in arrays correspond to each other. So, if you need fruit
number i, take bufferNames[i] and bufferPictures[i] in parallel way.
Ensure that names ARE parallel. Simply making the second array
elements from the first array elements.
As for random in range 0..n-1 excluding elements number i,j (j>i), count it so:
temp=random(n-3);
k=(temp>=i?temp+1:temp);
k=(k>=j?k+1:k);
And again, take bufferNames[k] and bufferPictures[k].
It is not simple, it is VERY simple.
Related
I am learning C++ and decided to make a card deck system using vectors. I have been able to randomly shuffle it, make 1 singular deck, and now I want to make a function that deals a hand from that deck.
Say I wanted a hand of 10 cards from a deck of 52 cards, therefore 42 cards would be left and the first 10 cards of the Deck vector will be taken and placed into the newHand vector but after looking for solutions on how to approach this using erase() and pop_back(), I cant seem to find an efficient or proper solution. However since I am new to C++ my code might not be the best thing to look at so I am open for suggestions on how to make this better, maybe with pointers? (Pointers are confusing to me and I am not sure when to use them).
Here are the main functions:
void Deck::deleteElement(std::vector<std::string> Deck, int index)
{
while (index--) {
Deck.erase(Deck.begin(), Deck.begin() + index);
}
}
void Deck::dealHand(int numOfCards, std::vector<std::string>& currentDeck, int numOfDecks)
{
std::vector<std::string> newHand;
static int remaining = deckSize(numOfDecks);
while (numOfCards-- && remaining != 0) {
newHand.push_back(currentDeck[numOfCards]);
--remaining;
} deleteElement(currentDeck, numOfCards);
for (auto & i : newHand) {
std::cout << i << " ";
}
std::cout << ",there are now " << remaining << " cards remaining" << std::endl;
}
I want to mention that deleteElement when using erase gives me this error
malloc: *** error for object 0x16f9ddf40: pointer being freed was not allocated
malloc: *** set a breakpoint in malloc_error_break to debug
I also could not find much on explaining what this means, if anyone can that would be a great help.
I would probably not bother with actually erasing elements from the deck's internal vector. That's because you might want to reshuffle and deal cards multiple times over the course of a game, which is easier if you just keep them all in the deck and track which ones have been dealt. And since almost everything container-related uses iterators, you can keep it short and simple like this:
#include <iterator>
#include <vector>
class Card {};
class Deck {
public:
using Cards = std::vector<Card>;
// Just an example constructor
explicit Deck(std::size_t size = 52)
: m_cards(size), m_current{m_cards.begin()}
{}
Cards dealHand(std::size_t count) {
auto begin = m_current;
std::ranges::advance(m_current, count, m_cards.end());
return Cards(begin, m_current);
}
std::size_t
size() const { return std::ranges::distance(m_current, m_cards.end()); }
private:
Cards m_cards;
Cards::iterator m_current;
};
int main() {
Deck deck {};
auto hand = deck.dealHand(10);
return deck.size();
}
While it's not strictly necessary to use std::ranges functions (they have equivalents in the std namespace), this part of C++20 is now widely supported. One advantage is that range algorithms accept entire ranges (such as containers) instead of only pairs of iterators, for example std::ranges::shuffle.
I have a question regarding this program. I am a beginner when it comes to programming and c++, and I'm trying to figure out two things.
why is this program not compiling (error: Using uninitialized memory 'total' - I have it defined as a variable??).
Could someone explain how the function outside of the main (sumUpTo) works? Specifically & vec and total, as I've never seen them before. Thanks.
/* 1) read in numbers from user input, into vector -DONE
2) Include a prompt for user to choose to stop inputting numbers - DONE
3) ask user how many nums they want to sum from vector -
4) print the sum of the first (e.g. 3 if user chooses) elements in vector.*/
#include <iostream>
#include <string>
#include <vector>
#include <numeric> //for accumulate
int sumUpTo(const std::vector<int>& vec, const std::size_t total)
{
if (total > vec.size())
return std::accumulate(vec.begin(), vec.end(), 0);
return std::accumulate(vec.begin(), vec.begin() + total, 0);
}
int main()
{
std::vector<int> nums;
int userInput, n, total;
std::cout << "Please enter some numbers (press '|' to stop input) " << std::endl;
while (std::cin >> userInput) {
if (userInput == '|') {
break; //stops the loop if the input is |.
}
nums.push_back(userInput); //push back userInput into nums vector.
}
std::cout << "How many numbers do you want to sum from the vector (the numbers you inputted) ? " << std::endl;
std::cout << sumUpTo(nums, total);
return 0;
}
Errors in your code -
int userInput, n, total;
.
.
.
std::cout << sumUpTo(nums, total);
Here you are declaring total and directly using it as a parameter to sumUpTo function. In that function you are using it in an comparison ( if (total > vec.size()) ). But, since you have never initialized it while declaration nor have you assigned it any value anywhere in the code, the compiler doesn't know what to make of that comparison that you are making since total doesn't have any value.
could someone explain how the function outside of main (sumUpTo)
works? Specifically '& vec' and 'total'
sumUpTo has the declaration as - int sumUpTo(const std::vector<int>& vec, const std::size_t total).
Here, you are expecting the function to take a vector of integers as parameters. But you probably have doubt with & that's before vec. That symbol just specifies that you are going to pass the vector as a reference and not by making a complete copy of the vector. In our regular passing, the vector we pass to function will get passed as a copy of our origin vector. But in this case, the vector is getting passed as a reference and not a copy of the original vector.
Do note that I have used the term reference and not pointers. If you are coming from C background, you could feel both are the same and in some cases, they might function a bit similar but there are few differences(some good answers on SO - 1, 2, 3 ) between them which you can read many good resources available online. Just understand that in this case, it prevents making a copy of the vector when it is passed to the function. If the function declaration wouldn't have mentioned that parameter to be const, you could also make changes in the vector which would also reflect in the original one as well (while they wouldn't have if you passed it normally rather than as reference).
std::size_t is a type that is used to represent the size of objects in bytes. It is an unsigned datatype and used whenever you are dealing with sizes of objects. You can also refer this if you are not sure about the difference between std::size_t and int ( which is what you might have been expecting total to be).
Lastly, it's obvious that const is being used in the function to ensure that the parameters that we are passing to function aren't getting modified in the function.
I want to create a function in which I can iterate over an array/vector containing a variable amount of strings, and I need to know the length of the strings before I send them to the function. How can I achieve this in an efficient way?
I have some loose idea of the function, but how do I efficiently sent an array/vector of strings to it and the size of all those strings combined. For example, the function could look something like this:
myFunc(vector<string> s, int totalWordLength) {
// Loop over strings in vector.
}
I could do something like this to create a vector of strings.
const char *args[] = {"12345", "678"};
vector<string> s(args, end(args));
But how do I then find out the size of the strings (8) in this without looping through it so that I can send it to myFunc(s, sizeOfStrings)?
If you have an idea to achieve the same result, by using an array instead or something, please let me know. I'm trying to do this as efficient as possible.
Iterate through container (container class irrelevant)
const char *args[] = {"12345", "678"};
vector<string> s(args, end(args));
size_t sizOfS = 0;
for( auto& item : s )
sizOfS += item.length();
Another way unites process of filling array and calculating length:
const char *args[] = {"12345", "678"};
std::vector<std::string> s;
s.reserve(sizeof(args)/sizeof(args[0]));
size_t sizOfS = 0;
for( const std::string& item : args )
{
sizOfS += item.length();
s.push_back(item);
}
Regardless of what you do, cost of the process would be O(n), where n = strings * their-total-length. There is no other defined way, but several functions which can turn loop into one-liner. Even if define your own container that would track length of strings, its cost would have same order.
Which container to use depends on what kind of actions you expect to perform, vector got constant cost of random access to container items, but linearly increasing cost of growing its storage. list may have cheap insertion\push cost but it got sequential iterator.
If you want to know the lengths of all of the strings in the vector and query it often (its not a one-off thing) then you can calculate the length of the strings when they are added together and store the total with the vector.
A quick example of this with a class:
class MyClassFoo {
public:
std::vector<std::string> items;
std::size_t total_item_sizes = 0;
void addItem(const std::string& item) {
total_item_sizes += item.length(); // Add its length to the total
items.emplace_back(item); // Add the item to the vector
}
}
Then you can pass this object around and query it.
If you want to be more efficent pass by reference or move single use parameters. This is important with something like a std::vector as you probably don't want to copy all it's elements.
As an aside it is unlikely this is actually neccasary, unless you are trying to sum the lengths of all the strings very frequently and there are a lot of them, your bottleneck will not be iterating over an std::vector. Your demand for 'efficency' smells like premature optimisation. Remember the 20-80 rule (80% of your program execution time is spent running 20% of your code).
Given your scenario, an approach could be to calculate the length of the strings at the time of construction of the vector.
One solution using a variadic template could be a wrapper like this (live):
#include <iostream>
#include <vector>
#include <string>
struct V
{
template <typename ... T>
V( T&& ... t ) : v{ std::forward<T>(t)... }
{
for ( const auto& s : v ) size += s.size();
}
std::vector<std::string> v;
std::size_t size {0};
};
int main()
{
const char *args[] = { "12345678", "6789", "1234", "5678" };
V obj ( std::begin(args), std::end(args) );
std::cout << "No. of Strings : " << obj.v.size() << '\n';
std::cout << "Total Length : " << obj.size << '\n';
return 0;
}
Output:
No. of Strings : 4
Total Length : 20
I want to create an MxN array (M particles in N dimensional space) filled with random numbers within an upper and lower boundary. I have a working python code that looks something like this:
# upper_bound/lower_bound are arrays of shape (dim,)
positions = np.random.rand(num_particle,dim)*(upper_bound-lower_bound)+lower_bound
Each row represents a particle, and each column represents a dimension in the problem space. So the upper_bound and lower_bound applies to each column. Now I want to translate the above code to c++, and I have something like this:
#include <iostream>
#include <vector>
#include <random>
#include <algorithm>
#include <ctime>
typedef std::vector<double> vect1d;
std::vector<vect1d> positions;
for (int i=0; i<num_particle; i++){
std::mt19937_64 generator(static_cast<std::mt19937::result_type>(time(0)));
std::uniform_real_distribution<double> distribution(0,1);
vect1d pos(dimension);
std::generate(pos.begin(),pos.end(),distribution(generator));
positions[i] = pos;
}
My problems:
It gives error regarding the generator, so I'm not sure if I set it properly. I'm also not sure how to use the std::generator. I'm trying it as I've looked at other similar posts and it seems that it allows me to generate more than one random number at a time, so I don't have to run it MxN times for each element. Is this true and how to correctly use it?
In python I can just vectorization and broadcasting to manipulate the numpy array. What's the most 'vectorized' way to do it in c++?
The above (incorrect) code only creates random number between 0 and 1, but how to incorporate the lower_bound and upper_bound as in the python version? I understand that I can change the values inside distribution(0,1), but the problem is the limits can be different for each dimension (so each column can have different valid range), so what's the most efficient way to generate random number, taking into account the range for each dimension?
Thanks
First of all, you're doing more work than you need to with your Python version, just use:
np.random.uniform(lower_bound, upper_bound, size=(num_particle, dim))
In your C++ attempt, the line
std::generate(pos.begin(),pos.end(),distribution(generator));
Is incorrect as the third argument must be a function not a value. A reasonable C++ equivalent would be:
using RandomVector = std::vector<double>;
using RandomMatrix = std::vector<RandomVector>;
template <typename Generator=std::mt19937_64>
RandomMatrix&
fill_uniform(const double low, const double high, RandomMatrix& result)
{
Generator gen {static_cast<typename Generator::result_type>(time(0))};
std::uniform_real_distribution<double> dist {low, high};
for (auto& col : result) {
std::generate(std::begin(col), std::end(col), [&] () { return dist(gen); });
}
return result;
}
template <typename Generator=std::mt19937_64>
RandomMatrix
generate_uniform(const double low, const double high,
const std::size_t ncols, const std::size_t nrows)
{
RandomMatrix result(ncols, RandomVector(nrows));
return fill_uniform<Generator>(low, high, result);
}
int main()
{
auto m = generate_uniform(2, 11, 2, 3);
for (const auto& col : m) {
for (const auto& v : col) {
std::cout << v << " ";
}
std::cout << '\n';
}
}
You could generalise this to generate arbitrary dimension tensors (like the NumPy version) without too much work.
I'll address them in random order:
3.You have several options - using one generator per row, created like distribution(row_lower_limit, row_upper_limit). Should be cheap enough to not cause issues. If you want to reuse the same generator, just do something like row_lower_limit + distribution(generator) * (row_upper_limit - row_lower_limit). The distribution is in both cases U[row_lower_limit, row_upper_limit].
2.The vectorization came from the numpy library, not from Python itself. It provided some nice UX at most. C++ doesn't have an equivalent library to numpy (though there's a lot of libraries for it as well - just nothing so univeral). You wouldn't be wrong by doing two nested fors. You'd perhaps be better served by just declaring a NxM array rather than a vector, like here.
1.Not sure how to help with the problem since we don't know the error. The cplusplus.com reference has an example of how to initialize this with reference to a random_device.
I want to create a program that uses a vector to sort it for testing reasons. So I want to calculate the CPU time by a benchmark that sorts the vector a certain amount of times. So the original vector needs to remain constant, and then use another vector so that it can be sorted.
So what I have done is...
#include <iostream>
#include <vector>
#include <random>
#include <chrono>
using namespace std;
typedef vector<int> intv;
int main(){
intv vi;
// Stuff to create my vector with certain characteristics...
intv vii=vi;
cout << "Size: \n";
cin >> tt ;
for(i=0; i<tt; ++i){
tb=sort(t,vii);
m=m+tb;
vii=vi;
}
m=m/tt;
cout << "BS" << m << "\n";
}
So I pass the vector by reference, and make a copy for each sorting so that I can sort it again. How can I do this a better way? Is it better to pass it by value, and in that case, Could someone provide me a minimum example of the best way to do this?
sort is a basic bubble sorting function:
double sort(int t, intv &vii){
vii.reserve(t);
bool swapped=true;
int a;
auto t0 =chrono::high_resolution_clock::now();
while (swapped==true){
for (int i=1; i<t; ++i){
swapped=false;
if (vii[i-1]>vii[i]){
a=vii[i];
vii[i]=vii[i-1];
vii[i-1]=a;
swapped=true;
}
}
t=t-1;
}
auto t1 = chrono::high_resolution_clock::now();
double T = chrono::duration_cast<chrono::nanoseconds>(t1-t0).count();
return T;
}
Once you have sorted, you have to do something that is equivalent to:
vii=vi;
I think assigning vi to vii will be the most efficient method of copying the contents of vi to vii. You can try:
size_t index = 0;
for ( auto const& val : vi )
{
vii[index++] = val;
}
However, I will be really surprised if the second method is more efficient than the first.
Nothing wrong with sorting in-place, and making a copy of the vector. The code you have should work, though it is not clear from where your parameter t is coming.
Note that the statement vii.reserve(t) is not doing anything useful in your sort routine: either t is less than or equal to the size of vii, in which case the reserve call does nothing, or it is greater than the size of vii, in which case you are accessing values outside the range of the vector. Better to check t against the vector size and throw an error or similar if it is too big.
Passing by value is straightforward: just declare your sort routine as double sort(int t, intv vii). When the function is called, vii will be copied from whichever vector you pass in as the second argument.
From a design point of view though, it is better to make a copy and then pass a reference. Sorting should change the thing being sorted; passing by value in the context of your code would mean that nothing would be able to inspect the sorted result.