I am trying to accomplish the following task:
List the students in alphabetic order, sorted by last name.
Do not change the given case of the names.
Do not change the output file format. (Firstname Lastname)
Just print the records in order by last name, i.e.
Annie J
Martin K
Toby L
This sort needs to be true alphabetical (not just the "lexicographical" sort).
The data was read in from a file and passed through a virtual function depending on what course this student was enrolled in. Here's what I have.
for (int i = 1; i < numStudents; i++)
{
if (( list[i] -> getLastname() ) < ( list[i - 1] -> getLastname() ))
{
Student *temp = list[i - 1];
ist[i - 1] = list[i];
list[i] = temp;
}
}
I've been working on this for a while now and I'm worried I've gone about this all wrong. Any tips/pointers appreciated!
I assume you have a struct like:
struct Student
{
std::string m_LastName;
std::string m_FirstName;
};
Now you need to make sure you can handle the case where two person have the same last name. In that case you want to look at the first name.
bool NameCompare(const Student &name1, const Student &name2)
{
if(name1.m_LastName == name2.m_LastName) {
return name1.m_FirstName < name2.m_FirstName;
}
return name1.m_LastName < name2.m_LastName;
}
Then just call sort on your list of Student
std::list<Student> student_list;
// add some Student to the list
student_list.sort(NameCompare);
Use string comparison function instead of the less than sign you used here:
if (( list[i] -> getLastname() ) < ( list[i - 1] -> getLastname() ))
Also here's a similar stackoverflow question (partially)
Is string::compare reliable to determine alphabetical order?
Try this reference, first you have to declare the size of the array of firstname and lastname using int z = sizeof(lastname, firstname)/sizeof(lastname[0], firstname[0]); and using sort(lastname,lastname+z); will sort the array of lastname then using loop to print the firstname with the sorted lastname.
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
string firstname[] = {"Michael", "Patricia", "Joseph", "Elizabeth", "Charles", "Barbara", "Thomas", "Margaret", "Robert", "Sarah"};
string lastname[] = {"Smith", "Johnson", "Williams", "Brown", "Jones", "Miller", "Davis", "Garcia", "Rodriguez", "Wilson"};
int z = sizeof(lastname, firstname)/sizeof(lastname[0], firstname[0]);
sort(lastname,lastname+z); //Use the start and end like this
for(int y = 0; y < z; y++){
cout << firstname[y]<< " " << lastname[y] << endl;
}
return 0;
}
Related
I am having trouble adding objects to a list.
I want to make a List of Persons, and I know the size of the list is fixed at 5 people.
Each Person has an age (int) and a gender (string).
I want to add the Persons to the List, but I don't know how, I've only worked with integers now that I think of it.
Below is what I have so far.
The random age and gender is working, however clunky that is.
I'm thinking instead of creating the Persons as I did, maybe somehow I should create them dynamically in a for loop which will somehow generate the age and gender per loop iteration? Maybe the list should be pointers to the Person objects.
#include <iostream>
#include <list>
#include <memory>
using namespace std;
class Person {
private:
const int OLDEST_AGE = 100;
const int YOUNGEST_AGE = 1;
int age;
string gender;
public:
Person()
{
age = generateAge();
gender = generateGender();
}
// Person: generate random age for Person, from 1-100
int generateAge() {
int randomAge;
randomAge = rand() % (OLDEST_AGE - YOUNGEST_AGE + 1) + YOUNGEST_AGE;
return randomAge;
};
// Person: generate random gender for Person, Male or Female
string generateGender() {
int genderNumber;
genderNumber = rand() % (1 - 0 + 1) + 0;
if (genderNumber == 1)
return "Male";
else
return "Female";
};
void getStats() {
cout << "Person Age: " << age << endl;
cout << "Person Gender: " << gender << endl;
};
};
int main()
{
Person P1, P2, P3, P4, P5;
// Just to see if the objects are created
P1.getStats();
P2.getStats();
P3.getStats();
P4.getStats();
P5.getStats();
list<Person> myList;
list<Person>::iterator IT;
for (int i = 1; i <= 5; i++)
//don't know how to add each Person to the list
myList.push_back(P1);
cout << "myList contains: ";
for (IT = myList.begin(); IT != myList.end(); IT++)
// similar to above, how do I get the list to print each object's stats
P1.getStats();
cout << endl;
return 0;
}
Using vector would be better in your case if you want to add a lot of elements one after the other as specified in another response to another question comparing list and vector.
Back to the question, as some comments specified, declaring a variable for each person is not a good practice. What you could do instead is to populate your list with a loop like so:
for(int i = 0; i < 5; i++)
myList.push_back(Person());
Then to access the objects you would just loop through the list again wherever you need to.
for(int i = 0; i < 5; i++)
myList[i].getStats();
You can create a vector, and run through a loop where you instantiate the person, and then push them into the vector. This way, you won't need to create separate person variables like p1, p2, etc., and your vector would hold all the "Person" objects.
vector<Person> people;
for (int i = 0; i < 5; i++) {
people.push_back(Person());
}
for (Person person : people) {
person.getStats();
}
I'm using C++98, I have a vector with the elements 13 m 1.5 0.6 and I would like to paste them into this string accordingly.
The length of Object 1 is %d%s, weight is %dkg, friction coefficient = %f.
The output will be
The length of Object 1 is 13m, weight is 1.5kg, friction coefficient = 0.6.
I tried it in a for loop but I'm not sure how to update the string after paste the 1st element. Any idea on this?
Thanks for help.
Edited:
The vector and str are just example. While, the number of element in vector will always be the same as the number of delimiter (%d, %s, %f) in the str.
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<string> values;
values.push_back("13");
values.push_back("m");
values.push_back("1.5");
values.push_back("0.6");
string str = "The length of Object 1 is %d%s, weight is %dkg, friction coefficient = %f.";
string str2 = "%d";
string str_crop;
string unk;
string final;
size_t found = str.find(str2);
if (found != std::string::npos)
{
str_crop = str.substr(0, found);
}
for (int i = 0; i < values.size(); i++) {
unk = values[i];
str_crop += unk;
}
final = str_crop;
cout << final << endl;
return 0;
}
I think I understood what you meant to do, I'd say you could use printf but since you want to use cout I suggest using a logic somewhat like this:
#include <iostream>
#include <vector>
#include <string> //included string for find, length and replace
using namespace std;
int main()
{
vector<string> values;
values.push_back("13");
values.push_back("m");
values.push_back("1.5");
values.push_back("0.6");
string str = "The length of Object 1 is %v%v, weight is %vkg, friction coefficient = %v.";
string str2 = "%v"; //i have swapped the "%d" to make it a "%v", representating value, to make it not too similar to C
string final;
int valloc = 1; //if you ever decide to add more values to that vector
for (int i=0;i<4;i++) {
int oc = str.find(str2);
if (oc < str.length()+1 && oc > -1) {
final=str.replace(oc,2,values[i+(valloc-1)]);
}
}
std::cout << final;
return 0;
}
Explaining what it does is:
1- takes a string
2- finds every occurance of the string's %v to replace
3- replaces it with the proper value from the vector
Write a void function called string_list_sort() that reads in any number of strings (duplicates are allowed) from cin, stores them in a vector, and then sorts them. Don’t use the standard C++ sort function here — use the version of quicksort that you created.
My problem is I tried to use strcmp() but I got a lot of errors, so I tried this method, but I have a problem with char val = v[end]. I am not sure how to compare two std::string values.
I changed char to string and it works. Now my problem is for example v = {" apple", "car", "fox", " soap", "foz"}; the result I get is apple, soap, car, fox, foz which is not in alphabetical order
#include <iostream>
#include <string>
#include <cstdio>
#include <cstring>
#include <vector>
#include "error.h"
using namespace std;
void string_list_sort(vector<string> v){
string line;
while (getline(cin, line)){
if (line.empty()){
break;
}
v.push_back(line);
}
}
int partition(vector<string>&v, int begin, int end)
{
char val = v[end];
char temp;
int j = end;
int i = begin - 1;
while (true)
{
while (v[++i] < val)
while (v[--j] > val)
{
if (j == begin)
break;
}
if (i >= j)
break;
temp = v[i];
v[i] = v[j];
v[j] = temp;
}
temp = v[i];
v[i] = v[end];
v[end] = temp;
return i;
}
void quicksort(vector<string>& v, int begin, int end)
{
if (begin < end)
{
int p = partition(v, begin, end);
quicksort(v, begin, p - 1);
quicksort(v, p + 1, end);
}
}
void quick_sort(vector<string>& v)
{
quicksort(v, 0, v.size() - 1);
}
int main()
{
vector<string> v;
v =
{ " this is a test string,.,!"};
string word;
while (cin >> word)
{
v.push_back(word);
}
quick_sort(v);
for (int i = 0; i < v.size(); i++)
{
cout << v[i] << " ";
}
}
OP almost has a sorting function. Two mistakes in particular stand out:
char val = v[end];
char temp;
v is a vector<string> so v[end] will return a string.
string val = v[end];
string temp;
Takes care of that and makes the program compile and successfully sort. There is no need to go inside the strings to compare character by character. string does that work for you.
The second problem: Quicksort's partition function is supposed to look like (Looting from wikipedia here)
algorithm partition(A, lo, hi) is
pivot := A[lo]
i := lo – 1
j := hi + 1
loop forever
do
i := i + 1
while A[i] < pivot
do
j := j – 1
while A[j] > pivot
if i >= j then
return j
swap A[i] with A[j]
and OP's partition function has picked up a bunch of extra baggage that needs to be removed to get an optimal mark from their instructor. Take a look at the above pseudo implementation and compare it with yours. You may see the mistakes right way, but if not, stand on the shoulders of giants and translate it into C++ (hints: := is plain old = in C++, and you'll need to add some ;s and braces). Debug the result as required. I won't translate it because that would almost totally defeat the point of the assignment.
Side notes (gathering a few important comments):
When writing a test driver don't take in user input until you know the algorithm works. Start with preloaded input that is easy to visualize like
int main()
{
vector<string> v{"C","B","A"};
quick_sort(v);
for (size_t i = 0; i < v.size(); i++)
{
cout << v[i] << " ";
}
}
When the output is "A B C ", change the input to something more complicated, but still easy to visualize
vector<string> v{"A","C","Q","B","A"};
And when that works go nuts and feed it something nasty. I like the Major General's Song from the Pirates of Penzance.
You can compare strings using std::string::compare() or relational operators.
It looks like you've tried using relational operators here, but as #user4581301 pointed out, in partition() on the first line, you have
char val = v[end];
However, v[end] is of type 'string', not 'char'. If you declare val and temp as string instead of char, you can sort them with the relational operators you have, and I think you'll be fine.
compare() documentation: fttp://www.cplusplus.com/reference/string/string/compare/
Relational operators: http://www.cplusplus.com/reference/string/string/operators/
i can't make program that reads from file words ( there is no limit of words or length to them ) with same first letter and last. I use class and object and first of all i can't make reading them
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
using namespace std;
class Texts{
public:
void Realding(string &All);
void Searching(string &text, char *Word);
};
int main()
{
Texts A;
string Text; char word[40];
A.Reading(Text);
A.Searching(Text, word);
system("PAUSE");
}
void Texts::Reading(string &All)
{
string temp;
ifstream read("Text.txt");
while (getline(read, temp)) { All += temp; All += "\n"; }
cout << All;
}
void Texts::Searching(string &text, char *Word)
{
int i = 0;
int j = 0;
int letters = 0;
int zodz = 0;
int index = 0;
while (1)
{
if (text[i] == ' ' || text[i] == '\0')
{
zodz++;
if (text[0] == text[i - 1])
{
letters = j;
for (int l = 0; l < letters; l++)
{
//cout << text[l];
}
j = 0;
}
if (text[i + 1 - j] == text[i - 1])
{
letters = j;
for (int l = i - j; l < letters; l++)
{
// cout << text[l];
}
j = 0;
}
}
if (text[i] == '\0') break;
else
i++;
j++;
}
}
I can't make it properly read from file... Text.txt looks like
asdfa su egze hah ktis faf
And how later when selected words with first and last same letter to assign to array, that later to sort them in alphabetical order. Thanks if someone helps me.
Reading from file:
std::ifstream in(NameOfFile);
std::string word;
while (in >> word) //will stop when word can't be read. probably bad file or end of file
{
// do something with word
}
Find word with same first and last letter
if (word.front() == word.back())
{
// do something with word
}
Note this does not handle words with capitalized letters. It would not find "Mom". It will likely crash over empty words. Both have trivial fixes.
Assign word to array
array[index++] == word;
This assumes you want to advance the index after inserting into the array. Please note the program will behave poorly if the array is overfilled. If you are allowed to by the assignment, please consider using a std::vector.
Sorting the array
std::sort(array, array + index);
This assumes you are allowed to use std::sort. Again, if possible use a std::vector in place of the array. index is assumed to be the value of index from the adding example above after all of the adding has been done. If you are NOT allowed to use std::sort ask another question. It's a lengthy topic.
For some reason I cannot get this sort the names correctly. Can anyone tell me what is wrong with it? As far as I can tell the problem is that the strings are not compared correctly. I have tried string comparisons before, and I know this kind of code should work. It really has me stumped.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
void sortNames(vector<string> &);
void main()
{
vector<string> namesList;
ifstream namesFile;
namesFile.open("Names.txt");
// Make sure the file exists.
if (namesFile)
{
// Get the names from the file.
string name;
while (getline(namesFile, name))
namesList.push_back(name);
// Sort the imported names.
sortNames(namesList);
for (int i = 0; i < namesList.size(); i++)
cout << namesList[i] << endl;
}
else
{
cout << "Data files are missing";
}
namesFile.close();
}
void sortNames(vector<string> &list)
{
for (int i = 0; i < list.size(); i++)
{
// Find the lowest value after i.
int lowIndex = i;
for (int j = i + 1; j < list.size(); j++)
{
string name = list[i];
string name2 = list[j];
if (name > name2)
lowIndex = j;
}
// Flip the elements if there was a value lower than i.
if (i != lowIndex)
{
string temp = list[i];
list[i] = list[lowIndex];
list[lowIndex] = temp;
}
}
}
Here is the problem: this line
string name = list[i];
should be
string name = list[lowIndex];
Your current implementation compares the element at j not to the smallest string that you have found so far, but to the string at index i. That is incorrect, because it does not find the smallest remaining string: instead, it finds the last string in the vector that is smaller than the current element at index i, which is not what you want.
rather than string name = list[i];, you want string name = list[lowIndex];