How to print uncommon value between 2 array? - c++

I wanna compare value that stored in filename[i] and filename[j] and print out the value in filename[i] that do not have the same filename as in filename[j]. I know it is possible to do using set_difference and sort solution but I do not know exactly to write the sort and set_differences code. Here i provide my original code so that u can test it out and more understand what I'm trying to do.
my full code:
#include <string>
#include <iostream>
#include <ctime> //important when to make random filename- srand(time(0))
#include <opencv2\opencv.hpp> //important when using opencv
#include <vector> //when using vector function
using namespace std;
using namespace cv; //important when using opencv
int main(int argc, char* argv[]) {
vector<String> filenames;
int a, i;
srand(time(0)); //seed random filenames - for random filename
// Get all jpg in the folder
cv::glob("C:\\Users\\x\\Documents\\Aggressive\\abc", filenames);
for (size_t i = 0; i < filenames.size(); i++)
{
Mat im = imread(filenames[i]); //read the filename location
std::cout << "\n";
std::size_t found = filenames[i].find_last_of("//\\");
//std:cout << " file: " << filenames[j].substr(found + 1) << '\n'; //display filename and its format (.jpg)
std::string::size_type const p(filenames[i].substr(found + 1).find_last_of('.')); //eg: 2.jpg then it will find the last '.'
std::string file_without_extension = filenames[i].substr(found + 1).substr(0, p); //eg: 2
std::cout << " file : " << filenames[i].substr(found + 1).substr(0, p); //display filename without .jpg
}
cout << "\n";
cout << "There's " << filenames.size() << " files in the current directory.\n" << endl; // total file in the specific directory
cout << "Enter array size: \n";
cin >> a;
for (int j = 0; j < filenames.size(); j++) {
//generate random filename
int index = rand() % filenames.size(); //random based on total of the file in the directory
//cout << filenames[index] << endl; //display the random number but might be redundant
//swap filenames[j] with filenames[index]
string temp = filenames[j];
filenames[j] = filenames[index];
filenames[index] = temp;
}
for (int j = 0; j < a; j++) {
//cout << "Random image selected:" << filenames[j] << endl; //basically to avoid the redundant random filename
Mat im = imread(filenames[j]); //read filename location
std::size_t found = filenames[j].find_last_of("//\\");
//std:cout << " file: " << filenames[j].substr(found + 1) << '\n'; //display filename and its format (.jpg)
std::string::size_type const p(filenames[j].substr(found + 1).find_last_of('.')); //eg: 2.jpg then it will find the last '.'
std::string file_without_extension = filenames[j].substr(found + 1).substr(0, p); //eg: 2
std::cout << " file: " << filenames[j].substr(found + 1).substr(0, p); //display filename without .jpg
string written_directory = "C:/Users/x/Documents/folder/" + filenames[j].substr(found + 1).substr(0, p) + ".jpg"; // write filename based on its original filename.
imwrite(written_directory, im);
}
return 0;
}

In my opinion this is a perfect example of an XY Problem. From you question, from your code and even from the comments, people do not really understand what you want to do. With that I mean, what do you want to achieve?
It is a vague guess that you want to copy a specified number of random selected JPEG files from one directory to the other. And that you want to show the filenames of the files that will not be copied.
Let me give you some examples, what is the reason for all this confusion.
First and most important, you do not show the full code. Definitions and variable types and functions are misssing an. This is also not a Minimum, Reproducable Example. And the description in your question is hard to understand.
I have two set of array
You have "two set array"? Do you mean, you have 2 [std::set][3] of [std::array][3]. Or maybe you have simply 2 [std::vector][3] of std::string. From what we can see in the code, we could assume a std::vector<std::string>>, but we do not know, because you did not show the feinition of "filenames".
Then, you are talking about "2" something. But we do see only one "filenames". So, 2 or 1?
in a comment you are writing
in the array 2 i had a random filename based on the size of array that an user entered
My guess is that you do not want to have a random filename, but you want to select filenames with a random index from the first vector and put it into a 2nd vector? But we can see only 1 vector "filenames" where you do some random swapping activity.
Then you have written
imread is actually to read the whole file in the folder of directory
This function is very important, what does it do? And what do you mean by "read the file"? Do you mean "filename", so the name of the file? Or the contents of the file? And what is the meaning of "folder of directory"? All filenames in one folder? Or subfolder of a directory entry?
So now my objective is to print out all the file that do not have same filename in the array 2
Again, do we really have 2 arrays(vector)? are they different?
And then, where do you copy the files?
So, you see, it is very hard to understand. Even, if people would like to help you, they cannot, because they do not understand you. Better to show a link to your original home work. Then people can help you. Members here on Stack Overflow want to help. But please allow them to do so.
Here I give you an abstract example for the random selection problem and set_difference problem:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <random>
int main() {
// Define 2 Vectors for filenames
// This vector is an example for files that could be in a specified directory
std::vector<std::string> fileNamesInDirectory{"8.jpg","5.jpg", "6.jpg", "9.jpg", "1.jpg", "4.jpg", "2.jpg", "3.jpg", };
// Print the filenames as information for the user
for (size_t i = 0U; i < fileNamesInDirectory.size(); ++i) {
std::cout << fileNamesInDirectory[i] << "\n";
}
// Next: Select randomly a given number of filenames from the above vector
// So, first get the number of selections. Inform the user
std::cout << "\nEnter a number of filenames that should be copied randomly. Range: 1-"<< fileNamesInDirectory.size()-1 << "\t";
size_t numberOfSelectedFileNames{};
std::cin >> numberOfSelectedFileNames;
// Check for valid range
if (numberOfSelectedFileNames == 0 || numberOfSelectedFileNames >= fileNamesInDirectory.size()) {
std::cerr << "\n*** Error. Wrong input '" << numberOfSelectedFileNames << "'\n";
}
else {
// Copy all data from fileNamesInDirectory
std::vector<std::string> selection{ fileNamesInDirectory };
// Shuffle the data randomly: Please see here: https://en.cppreference.com/w/cpp/algorithm/random_shuffle
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(selection.begin(), selection.end(), g);
// Resize to the number, given by the user
selection.resize(numberOfSelectedFileNames);
// Now we have a random list of filenames
// Show, what we have so far. Now, because we are learning, we will use the range based for
std::cout << "\n\nOriginal file names:\n";
for (const std::string& s : fileNamesInDirectory) std::cout << s << "\n";
std::cout << "\n\nRandomly selected file names:\n";
for (const std::string& s : selection) std::cout << s << "\n";
// Sort both vectors
std::sort(fileNamesInDirectory.begin(), fileNamesInDirectory.end());
std::sort(selection.begin(), selection.end());
// Show again to the user:3
std::cout << "\n\nOriginal file names sorted:\n";
for (const std::string& s : fileNamesInDirectory) std::cout << s << "\n";
std::cout << "\n\nRandomly selected file names sorted:\n";
for (const std::string& s : selection) std::cout << s << "\n";
// Now, find out the difference of both vectors, meaning, what will not be selected and later copied
std::vector<std::string> difference{};
// Calculate the difference with a std::algorithm: https://en.cppreference.com/w/cpp/algorithm/set_difference
std::set_difference(fileNamesInDirectory.begin(), fileNamesInDirectory.end(), selection.begin(), selection.end(), std::back_inserter(difference));
std::cout << "\n\nThe following file names have not been selected:\n";
for (const std::string& s : difference) std::cout << s << "\n";
}
return 0;
}
If you are more advanced then you can and will use functions from the C++ filesystem library. That will make life easier . . .

Related

Randomize distinct cout statements (like getting 4 possible answers for a quiz)

This code is outputting 1 correct answer - which is always the one associated with 'random_number', so the first cout statement is always true. But who wants this kind of a quiz?
srand((int)time(0));
int random_number = rand() % max_event_number;
std::cout <<"\n" << final_years[random_number] << std::endl;
std::cout << "\n" << final_years[1 + random_number] << std::endl;
std::cout << "\n" << final_years[2 + random_number] << std::endl;
std::cout << "\n" << final_years[3 + random_number] << std::endl;
std::cout << "\n" << "Please type the correct year : " << std::endl;
Yes..., I can generate some random answers from the entire array, but they won't necessarily include the correct answer.
I don't want to change the way the correct answer is generated by the first 'random_number', because it takes only one line of code to check if the answer is true or not...
If only I could shuffle every time those 4 cout statement...
How would you do it?
Maybe not the best solution, but it works:
#include <iostream>
#include <string>
#include <cstdlib>
#include <algorithm>
#include <vector>
std::vector<std::string> possible_answers = { final_years[random_number], final_years[1 + random_number], final_years[2 + random_number], final_years[3 + random_number] };
// I initialized a vector like an array with all the 4 answers, including the correct one (since C++11)
std::vector<std::string>::iterator it;
it = possible_answers.begin();
std::random_shuffle(possible_answers.begin(), possible_answers.end()); //shuffled its contents
for (it = possible_answers.begin(); it < possible_answers.end(); it++) //some tinkering to output vector's content
std::cout <<"\n" << *it;
Now the randomly generated numbers are displayed in a random order on the screen, but the correct answer is always the first generated number.

Mean and Mode of vector array - How can I make a smaller improvement in the function

Doing an exercise to find the mean and mode of a list of numbers input by a user. I have written the program and it works, but I'm wondering if my function 'calcMode' is too large for this program. I've just started looking into functions which is a first attempt. Would it be better to write smaller functions? and if so what parts can I split? Im pretty new to C++ and also looking if I can improve this code. Is there any changes I can make to make this run more efficient?
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int calcMean(vector<int> numberList)
{
int originNumber = numberList[0];
int nextNumber;
int count = 0;
int highestCount = 0;
int mean = 0;
for (unsigned int i = 0; i <= numberList.size() - 1; i++)
{
nextNumber = numberList[i];
if (nextNumber == originNumber)
count++;
else
{
cout << "The Number " << originNumber << " appears " << count << " times." << endl;
count = 1;
originNumber = nextNumber;
}
}
if (count > highestCount)
{
highestCount = count;
mean = originNumber;
}
cout << "The Number " << originNumber << " appears " << count << " times." << endl;
return mean;
}
int main()
{
vector<int> v;
int userNumber;
cout << "Please type a list of numbers so we can arrange them and find the mean: "<<endl;
while (cin >> userNumber) v.push_back(userNumber);
sort(v.begin(), v.end());
for (int x : v) cout << x << " | ";
cout << endl;
cout<<calcMean(v)<<" is the mean"<<endl;
return 0;
}
One thing to watch out for is copying vectors when you don't need to.
The function signature
int calcMode(vector<int> numberList)
means the numberList will get copied.
int calcMode(const & vector<int> numberList)
will avoid the copy. Scott Meyer's Effective C++ talks about this.
As an aside, calling is a numberList is misleading - it isn't a list.
There are a couple of points that are worth being aware of in the for loop:
for (unsigned int i = 0; i <= numberList.size()-1; i++)
First, this might calculate the size() every time. An optimiser might get rid of this for you, but some people will write
for (unsigned int i = 0, size=numberList.size(); i <= size-1; i++)
The size is found once this way, instead of potentially each time.
They might even change the i++ to ++i. There used to a potential overhead here, since the post-increment might involve an extra temporary value
One question - are you *sure this gives the right answer?
The comparison nextNumber == originNumber is looking at the first number to begin with.
Try it with 1, 2, 2.
One final point. If this is general purpose, what happens if the list is empty?
Would it be better to write smaller functions?
Yes, you can make do the same job using std::map<>; which could be
a much appropriate way to count the repetition of the array elements.
Secondly, it would be much safer to know, what is the size of the
array. Therefore I suggest the following:
std::cout << "Enter the size of the array: " << std::endl;
std::cin >> arraySize;
In the calcMode(), you can easily const reference, so that array
will not be copied to the function.
Here is the updated code with above mentioned manner which you can refer:
#include <iostream>
#include <algorithm>
#include <map>
int calcMode(const std::map<int,int>& Map)
{
int currentRepetition = 0;
int mode = 0;
for(const auto& number: Map)
{
std::cout << "The Number " << number.first << " appears " << number.second << " times." << std::endl;
if(currentRepetition < number.second )
{
mode = number.first; // the number
currentRepetition = number.second; // the repetition of the that number
}
}
return mode;
}
int main()
{
int arraySize;
int userNumber;
std::map<int,int> Map;
std::cout << "Enter the size of the array: " << std::endl;
std::cin >> arraySize;
std::cout << "Please type a list of numbers so we can arrange them and find the mean: " << std::endl;
while (arraySize--)
{
std::cin >> userNumber;
Map[userNumber]++;
}
std::cout << calcMode(Map)<<" is the mode" << std::endl;
return 0;
}
Update: After posting this answer, I have found that you have edited your function with mean instead of mode. I really didn't get it.
Regarding mean & mode: I recommend you to read more. Because in general, a data set can have multiple modes and only one mean.
I personally wouldn't split this code up in smaller blocks, only if i'd want to reuse some code in other methods. But just for this method it's more readable like this.
The order of excecution is aroun O(n) for calc which is quite oke if you ask me

how to put "a string",a number,"a string",another number in a string arra

I have question about putting data below in a string array , I mean that is it possible to do as bellow:
for(int i{};i<num;i++)
string[i]={"The degree of",i,"'th vertice is",degree[i]}
I have tried that and I know its not practical in c++ but is there any other way to do so, my goal is to return a string that number of each degree is saved in by a function called degree,as what I have mentioned (for example "The degree of 4'th vertice is 2") .
so is there possible to do so?
I want to call the function as below:
std::cout<<degree();
thanks for your attention.
Sure, you can put everything in a single string and put a newline ('\n') between each logical line. Just combine the code snippets given above:
std::string degrees()
{
std::string lines;
for(int i{};i<num;i++)
lines += "The degree of " + std::to_string(i) +
"'th vertice is " + std::to_string(degree[i]) + '\n';
return lines;
}
You could try something like this as well (edited to remove argument passing to degrees fnc, as OP doesn't want that):
#include <iostream>
#include <sstream>
std::vector<int> degree = { 1,5,4,8,2,12,4,30,45,22 };
std::string degrees()
{
std::ostringstream oss;
for (size_t i = 0; i < degree.size(); ++i)
oss << (i > 0 ? "\n" : "") << "The degree of " << i + 1 << "'th vertice is " << degree[i];
return oss.str();
}
int main()
{
std::cout << degrees() << std::endl;
return 0;
}
Prints:

C++ Usage of set, iterator, find line where duplicate was found

The program adds different strings to a set. The iterator checks the set for a certain string, what i want to achieve is to get the line where the iterator finds this certain string. Is it possible to get this with a set or do i have to create a vector? The reason i use sets is because i also want not to have duplicates in the end. It is a bit confusing i know, i hope you'll understand.
Edit: i want to get the line number of the original element already existing in the set, if a duplicate is found
#include <iostream>
#include <set>
#include <string>
#include <vector>
#include <atlstr.h>
#include <sstream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
set<string> test;
set<string>::iterator it;
vector<int> crossproduct(9, 0);
for (int i = 0; i < 6; i++)
{
crossproduct[i] = i+1;
}
crossproduct[6] = 1;
crossproduct[7] = 2;
crossproduct[8] = 3;
for (int i = 0; i < 3; i++)
{
ostringstream cp; cp.precision(1); cp << fixed;
ostringstream cp1; cp1.precision(1); cp1 << fixed;
ostringstream cp2; cp2.precision(1); cp2 << fixed;
cp << crossproduct[i*3];
cp1 << crossproduct[i*3+1];
cp2 << crossproduct[i*3+2];
string cps(cp.str());
string cps1(cp1.str());
string cps2(cp2.str());
string cpstot = cps + " " + cps1 + " " + cps2;
cout << "cpstot: " << cpstot << endl;
it = test.find(cpstot);
if (it != test.end())
{
//Display here the line where "1 2 3" was found
cout << "i: " << i << endl;
}
test.insert(cpstot);
}
set<string>::iterator it2;
for (it2 = test.begin(); it2 != test.end(); ++it2)
{
cout << *it2 << endl;
}
cin.get();
return 0;
}
"Line number" is not very meaningful to a std::set<string>,
because as you add more strings to the set you may change the
order in which the existing strings are iterated through
(which is about as much of a "line number" as the set::set template
itself will give you).
Here's an alternative that may work better:
std::map<std::string, int> test.
The way you use this is you keep a "line counter" n somewhere.
Each time you need to put a new string cpstot in your set,
you have code like this:
std::map<std::string>::iterator it = test.find(cpstot);
if (it == test.end())
{
test[cpstot] = n;
// alternatively, test.insert(std::pair<std::string, int>(cpstot, n))
++n;
}
else
{
// this prints out the integer that was associated with cpstot in the map
std::cout << "i: " << it->second;
// Notice that we don't try to insert cpstot into the map in this case.
// It's already there, and we don't want to change its "line number",
// so there is nothing good we can accomplish by an insertion.
// It's a waste of effort to even try.
}
If you set n = 0 before you started putting any strings in test then
(and don't mess with the value of n in any other way)
then you will end up with strings at "line numbers" 0, 1, 2, etc.
in test and n will be the number of strings stored in test.
By the way, neither std::map<std::string, int>::iterator nor
std::set<std::string>::iterator is guaranteed to iterate through
the strings in the sequence in which they were first inserted.
Instead, what you'll get is the strings in whatever order the
template's comparison object puts the string values.
(I think by default you get them back in lexicographic order,
that is, "alphabetized".)
But when you store the original "line number" of each string in
std::map<std::string, int> test, when you are ready to
print out the list of strings you can copy the string-integer pairs
from test to a new object, std::map<int, std::string> output_sequence,
and now (assuming you do not override the default comparison object)
when you iterate through output_sequence you will get its
contents sorted by line number.
(You will then probably want to get the string
from the second field of the iterator.)

How do you append an int to a string in C++? [duplicate]

This question already has answers here:
How to concatenate a std::string and an int
(25 answers)
Closed 6 years ago.
int i = 4;
string text = "Player ";
cout << (text + i);
I'd like it to print Player 4.
The above is obviously wrong but it shows what I'm trying to do here. Is there an easy way to do this or do I have to start adding new includes?
With C++11, you can write:
#include <string> // to use std::string, std::to_string() and "+" operator acting on strings
int i = 4;
std::string text = "Player ";
text += std::to_string(i);
Well, if you use cout you can just write the integer directly to it, as in
std::cout << text << i;
The C++ way of converting all kinds of objects to strings is through string streams. If you don't have one handy, just create one.
#include <sstream>
std::ostringstream oss;
oss << text << i;
std::cout << oss.str();
Alternatively, you can just convert the integer and append it to the string.
oss << i;
text += oss.str();
Finally, the Boost libraries provide boost::lexical_cast, which wraps around the stringstream conversion with a syntax like the built-in type casts.
#include <boost/lexical_cast.hpp>
text += boost::lexical_cast<std::string>(i);
This also works the other way around, i.e. to parse strings.
printf("Player %d", i);
(Downvote my answer all you like; I still hate the C++ I/O operators.)
:-P
These work for general strings (in case you do not want to output to file/console, but store for later use or something).
boost.lexical_cast
MyStr += boost::lexical_cast<std::string>(MyInt);
String streams
//sstream.h
std::stringstream Stream;
Stream.str(MyStr);
Stream << MyInt;
MyStr = Stream.str();
// If you're using a stream (for example, cout), rather than std::string
someStream << MyInt;
For the record, you can also use a std::stringstream if you want to create the string before it's actually output.
cout << text << " " << i << endl;
Your example seems to indicate that you would like to display the a string followed by an integer, in which case:
string text = "Player: ";
int i = 4;
cout << text << i << endl;
would work fine.
But, if you're going to be storing the string places or passing it around, and doing this frequently, you may benefit from overloading the addition operator. I demonstrate this below:
#include <sstream>
#include <iostream>
using namespace std;
std::string operator+(std::string const &a, int b) {
std::ostringstream oss;
oss << a << b;
return oss.str();
}
int main() {
int i = 4;
string text = "Player: ";
cout << (text + i) << endl;
}
In fact, you can use templates to make this approach more powerful:
template <class T>
std::string operator+(std::string const &a, const T &b){
std::ostringstream oss;
oss << a << b;
return oss.str();
}
Now, as long as object b has a defined stream output, you can append it to your string (or, at least, a copy thereof).
Another possibility is Boost.Format:
#include <boost/format.hpp>
#include <iostream>
#include <string>
int main() {
int i = 4;
std::string text = "Player";
std::cout << boost::format("%1% %2%\n") % text % i;
}
Here a small working conversion/appending example, with some code I needed before.
#include <string>
#include <sstream>
#include <iostream>
using namespace std;
int main(){
string str;
int i = 321;
std::stringstream ss;
ss << 123;
str = "/dev/video";
cout << str << endl;
cout << str << 456 << endl;
cout << str << i << endl;
str += ss.str();
cout << str << endl;
}
the output will be:
/dev/video
/dev/video456
/dev/video321
/dev/video123
Note that in the last two lines you save the modified string before it's actually printed out, and you could use it later if needed.
For the record, you could also use Qt's QString class:
#include <QtCore/QString>
int i = 4;
QString qs = QString("Player %1").arg(i);
std::cout << qs.toLocal8bit().constData(); // prints "Player 4"
cout << text << i;
One method here is directly printing the output if its required in your problem.
cout << text << i;
Else, one of the safest method is to use
sprintf(count, "%d", i);
And then copy it to your "text" string .
for(k = 0; *(count + k); k++)
{
text += count[k];
}
Thus, you have your required output string
For more info on sprintf, follow:
http://www.cplusplus.com/reference/cstdio/sprintf
cout << text << i;
The << operator for ostream returns a reference to the ostream, so you can just keep chaining the << operations. That is, the above is basically the same as:
cout << text;
cout << i;
cout << "Player" << i ;
cout << text << " " << i << endl;
The easiest way I could figure this out is the following..
It will work as a single string and string array.
I am considering a string array, as it is complicated (little bit same will be followed with string).
I create a array of names and append some integer and char with it to show how easy it is to append some int and chars to string, hope it helps.
length is just to measure the size of array. If you are familiar with programming then size_t is a unsigned int
#include<iostream>
#include<string>
using namespace std;
int main() {
string names[] = { "amz","Waq","Mon","Sam","Has","Shak","GBy" }; //simple array
int length = sizeof(names) / sizeof(names[0]); //give you size of array
int id;
string append[7]; //as length is 7 just for sake of storing and printing output
for (size_t i = 0; i < length; i++) {
id = rand() % 20000 + 2;
append[i] = names[i] + to_string(id);
}
for (size_t i = 0; i < length; i++) {
cout << append[i] << endl;
}
}
There are a few options, and which one you want depends on the context.
The simplest way is
std::cout << text << i;
or if you want this on a single line
std::cout << text << i << endl;
If you are writing a single threaded program and if you aren't calling this code a lot (where "a lot" is thousands of times per second) then you are done.
If you are writing a multi threaded program and more than one thread is writing to cout, then this simple code can get you into trouble. Let's assume that the library that came with your compiler made cout thread safe enough than any single call to it won't be interrupted. Now let's say that one thread is using this code to write "Player 1" and another is writing "Player 2". If you are lucky you will get the following:
Player 1
Player 2
If you are unlucky you might get something like the following
Player Player 2
1
The problem is that std::cout << text << i << endl; turns into 3 function calls. The code is equivalent to the following:
std::cout << text;
std::cout << i;
std::cout << endl;
If instead you used the C-style printf, and again your compiler provided a runtime library with reasonable thread safety (each function call is atomic) then the following code would work better:
printf("Player %d\n", i);
Being able to do something in a single function call lets the io library provide synchronization under the covers, and now your whole line of text will be atomically written.
For simple programs, std::cout is great. Throw in multithreading or other complications and the less stylish printf starts to look more attractive.
You also try concatenate player's number with std::string::push_back :
Example with your code:
int i = 4;
string text = "Player ";
text.push_back(i + '0');
cout << text;
You will see in console:
Player 4
You can use the following
int i = 4;
string text = "Player ";
text+=(i+'0');
cout << (text);
If using Windows/MFC, and need the string for more than immediate output try:
int i = 4;
CString strOutput;
strOutput.Format("Player %d", i);