-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Mohammed almakki exercies #88
base: main
Are you sure you want to change the base?
Changes from all commits
2252c62
55a3c17
66b9c7d
2d7dd69
07ee0cb
5986ad4
9fab113
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
cmake_minimum_required ( VERSION 3.14 ) | ||
|
||
project(newstarter) | ||
|
||
add_subdirectory ( ex01_basics ) | ||
add_subdirectory ( ex02_oo_basics ) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
This directory contains the template CMake projects for each of the exercises. | ||
|
||
Do not write your code for the exercises in here. Instead, make a copy of the directory containing this file and name your new directory `firstname_surname`. The CMake files contain relative paths so the new directory should be at the same level as the parent `template` directory. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
cmake_minimum_required ( VERSION 2.8.5 ) | ||
|
||
############################################################################### | ||
# Setup | ||
############################################################################### | ||
# Name | ||
project ( WordCounter ) | ||
|
||
# Find custom cmake modules | ||
set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../CMake") | ||
|
||
# Common setup | ||
include ( CommonSetup ) | ||
|
||
############################################################################### | ||
# Executable | ||
############################################################################### | ||
|
||
set ( SRC_FILES | ||
src/main.cpp | ||
# add any additional source files here | ||
) | ||
|
||
set ( HDR_FILES | ||
# add any additional header files here | ||
) | ||
|
||
add_executable ( WordCounter ${SRC_FILES} ${HDR_FILES} ) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
#include <iostream> | ||
#include <fstream> | ||
#include <sstream> | ||
#include <string> | ||
#include <regex> | ||
#include <unordered_map> | ||
#include <cstring> | ||
#include <iomanip> | ||
|
||
std::string readFile(const std::string &filepath) | ||
{ | ||
std::ifstream inputStream(filepath); | ||
|
||
if (inputStream) | ||
{ | ||
std::ostringstream ss; | ||
ss << inputStream.rdbuf(); | ||
return ss.str(); | ||
} | ||
else | ||
{ | ||
throw std::invalid_argument("Invalid path. Please make sure the file path is correct and the file exists."); | ||
} | ||
} | ||
|
||
std::vector<std::string> tokenizeFile(const std::string &file) | ||
{ | ||
std::regex re("[-\\s]"); | ||
std::sregex_token_iterator first{file.begin(), file.end(), re, -1}, last; | ||
std::vector<std::string> tokens{first, last}; | ||
return tokens; | ||
} | ||
|
||
std::unordered_map<std::string, uint32_t> countWords(const std::vector<std::string> words) | ||
{ | ||
std::unordered_map<std::string, uint32_t> wordsCounts; | ||
for (auto word : words) | ||
{ | ||
std::transform( | ||
word.begin(), word.end(), word.begin(), | ||
[](unsigned char c) | ||
{ return std::tolower(c); }); | ||
word.erase(std::remove_if(word.begin(), word.end(), ispunct), word.end()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The task specifies only needing to consider There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As I understood, the comparison should be punctation insensitive. So for example, "what's" should be equal to "whats" but replacing it with whitespace will result in the word not being included (not longer than 4). So in this line, I just remove every punctuation mark. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In that case I think you may be right |
||
if (word.length() > 4) | ||
{ | ||
wordsCounts[word]++; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you should have a check to see if word is currently in the wordCounts map There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmmm, why is it needed? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ultimatly it is not required for it to work, but it is better practice to have the check when performing an action on an object in a map where it is not certain that the object will exist. |
||
} | ||
} | ||
return wordsCounts; | ||
} | ||
|
||
void sortAndWriteWords(const std::unordered_map<std::string, uint32_t> &wordsCounts, const std::string &outputDir) | ||
{ | ||
std::vector<std::pair<std::string, int>> wordsCountsPairs; | ||
for (auto &pair : wordsCounts) | ||
{ | ||
wordsCountsPairs.push_back(pair); | ||
} | ||
std::sort( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good sorting process. |
||
wordsCountsPairs.begin(), wordsCountsPairs.end(), | ||
[](auto &left, auto &right) | ||
{ | ||
return left.second > right.second; | ||
}); | ||
|
||
std::ofstream outputFile(outputDir + "\\output.txt"); | ||
|
||
outputFile << std::setw(20) << std::left << "Word" << std::setw(20) << std::left << "Usage" | ||
<< "\n\n"; | ||
|
||
for (auto &it : wordsCountsPairs) | ||
{ | ||
outputFile << std::setw(20) << std::left << it.first << std::setw(20) << std::left << it.second << "\n"; | ||
} | ||
|
||
outputFile.close(); | ||
std::cout << "Found " << wordsCountsPairs.size() << " words and their counts have been successfully written in this path: " << outputDir + "\\output.txt" | ||
<< "\n"; | ||
} | ||
|
||
int main(int, char **) | ||
{ | ||
while (true) | ||
{ | ||
std::cout << "Welcome to the Word Counter program!" | ||
<< "\n\n"; | ||
std::cout << "This program will count the number of occurrences of unique words (longer than 4 characters and split hyphenated words, treating each part as different words)" | ||
<< "\n"; | ||
std::cout << "The count will be case and punctuation insensitive" | ||
<< "\n\n"; | ||
std::cout << "Please enter the path of the file:" | ||
<< "\n"; | ||
std::string inputFilePath; | ||
getline(std::cin, inputFilePath); | ||
|
||
std::string file; | ||
try | ||
{ | ||
file = readFile(inputFilePath); | ||
if (file.empty()) | ||
{ | ||
std::cout << "Note: " | ||
<< "This file is empty so the output will be an empty file." | ||
<< "\n"; | ||
} | ||
} | ||
catch (std::invalid_argument e) | ||
{ | ||
std::cerr << "Error:" << e.what() << "\n\n"; | ||
continue; | ||
} | ||
|
||
std::vector<std::string> tokenizedFile = tokenizeFile(file); | ||
std::unordered_map<std::string, uint32_t> wordsCounts = countWords(tokenizedFile); | ||
|
||
std::string outputFileDir = inputFilePath.substr(0, inputFilePath.rfind('\\')); | ||
sortAndWriteWords(wordsCounts, outputFileDir); | ||
|
||
break; | ||
} | ||
|
||
return 0; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
cmake_minimum_required ( VERSION 2.8.5 ) | ||
|
||
############################################################################### | ||
# Setup | ||
############################################################################### | ||
# Name | ||
project ( Shapes ) | ||
|
||
# Find custom cmake modules | ||
set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../CMake") | ||
|
||
# Common setup | ||
include ( CommonSetup ) | ||
|
||
############################################################################### | ||
# Executable | ||
############################################################################### | ||
|
||
set ( SRC_FILES | ||
src/main.cpp | ||
src/ShapeSorter.cpp | ||
) | ||
|
||
set ( HDR_FILES | ||
src/Shape.h | ||
src/ShapeSorter.h | ||
) | ||
|
||
add_executable ( Shapes ${SRC_FILES} ${HDR_FILES} ) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
#pragma once | ||
|
||
#include <string> | ||
#include <math.h> | ||
|
||
enum class ShapeType { Shape, Rectangle, Square, Circle, Triangle }; | ||
|
||
class Shape | ||
{ | ||
public: | ||
virtual inline double getArea() const = 0; | ||
virtual inline double getPerimeter() const = 0; | ||
|
||
virtual inline ShapeType getType() const = 0; | ||
virtual inline std::string toString() const = 0; | ||
|
||
inline int getSidesCount() const { | ||
return noOfSides; | ||
} | ||
|
||
Shape(const int& noOfSides) : noOfSides{noOfSides} {} | ||
|
||
private: | ||
const int noOfSides; | ||
}; | ||
|
||
class Rectangle : public Shape | ||
{ | ||
public: | ||
Rectangle(const double& side1, const double& side2) : side1{side1}, side2{side2}, Shape(2) {} | ||
|
||
inline ShapeType getType() const override | ||
{ | ||
return ShapeType::Rectangle; | ||
} | ||
|
||
inline double getArea() const override | ||
{ | ||
return side1 * side2; | ||
} | ||
|
||
inline double getPerimeter() const override | ||
{ | ||
return 2 * side1 + 2 * side2; | ||
} | ||
|
||
inline std::string toString() const override | ||
{ | ||
return "Rectangle(side1=" + std::to_string(side1) + ", side2=" + std::to_string(side2) + ")"; | ||
} | ||
|
||
private: | ||
double side1; | ||
double side2; | ||
}; | ||
|
||
class Square : public Rectangle | ||
{ | ||
public: | ||
Square(double side1) : side1{side1}, Rectangle(side1, side1) {} | ||
|
||
inline ShapeType getType() const override | ||
{ | ||
return ShapeType::Rectangle; | ||
} | ||
|
||
inline std::string toString() const override | ||
{ | ||
return "Square(side=" + std::to_string(side1) + ")"; | ||
} | ||
|
||
private: | ||
double side1; | ||
}; | ||
|
||
class Circle : public Shape | ||
{ | ||
public: | ||
Circle(double radius) : radius{radius}, Shape(0) {} | ||
|
||
inline ShapeType getType() const override | ||
{ | ||
return ShapeType::Circle; | ||
} | ||
|
||
inline double getArea() const override | ||
{ | ||
return M_PI * radius * radius; | ||
} | ||
|
||
inline double getPerimeter() const override | ||
{ | ||
return 2 * M_PI * radius; | ||
} | ||
|
||
inline std::string toString() const override | ||
{ | ||
return "Circle(radius=" + std::to_string(radius) + ")"; | ||
} | ||
|
||
private: | ||
double radius; | ||
}; | ||
|
||
class Triangle : public Shape | ||
{ | ||
public: | ||
Triangle(double height, double base) : height{height}, base{base}, Shape(3) {} | ||
|
||
inline ShapeType getType() const override | ||
{ | ||
return ShapeType::Triangle; | ||
} | ||
|
||
inline double getArea() const override | ||
{ | ||
return 0.5 * height * base; | ||
} | ||
|
||
inline double getPerimeter() const override | ||
{ | ||
return base + 2 * std::sqrt(height * height + (base * base) / 4); | ||
} | ||
|
||
inline std::string toString() const override | ||
{ | ||
return "Triangle(height=" + std::to_string(height) + ", base=" + std::to_string(base) + ")"; | ||
} | ||
|
||
private: | ||
double height; | ||
double base; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
#include "ShapeSorter.h" | ||
|
||
void ShapeSorter::filterAndPrintByPredicate(const std::vector<std::shared_ptr<Shape>> &shapes, const ShapeFilterPredicate &predicate) const | ||
{ | ||
for_each( | ||
shapes.begin(), shapes.end(), [predicate](auto shape) | ||
{ | ||
if(predicate(shape)) { | ||
std::cout << shape->toString() << " "; | ||
} }); | ||
std::cout << "\n"; | ||
} | ||
|
||
void ShapeSorter::printShapesWithType(const ShapeType &type) const | ||
{ | ||
filterAndPrintByPredicate(shapes, [type](const std::shared_ptr<Shape> &shape) | ||
{ return shape->getType() == type; }); | ||
} | ||
|
||
void ShapeSorter::printShapesWithSides(const int &sidesCount) const | ||
{ | ||
filterAndPrintByPredicate(shapes, [sidesCount](const std::shared_ptr<Shape> &shape) | ||
{ return shape->getSidesCount() == sidesCount; }); | ||
} | ||
|
||
void ShapeSorter::printOrderedShapesByArea() const | ||
{ | ||
auto sortedShapes = shapes; | ||
|
||
std::sort( | ||
sortedShapes.begin(), sortedShapes.end(), | ||
[](auto left, auto right) | ||
{ | ||
return left->getArea() > right->getArea(); | ||
}); | ||
|
||
filterAndPrintByPredicate(sortedShapes, [](const std::shared_ptr<Shape> &shape) | ||
{ return true; }); | ||
} | ||
|
||
void ShapeSorter::printOrderedShapesByPerimeter() const | ||
{ | ||
auto sortedShapes = shapes; | ||
|
||
std::sort( | ||
sortedShapes.begin(), sortedShapes.end(), | ||
[](auto left, auto right) | ||
{ | ||
return left->getPerimeter() > right->getPerimeter(); | ||
}); | ||
|
||
filterAndPrintByPredicate(sortedShapes, [](const std::shared_ptr<Shape> &shape) | ||
{ return true; }); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is the inent of this that the experssion match a hyphen of a whitespace, but a double backslash exits the special character.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This regex is used to split the string by two delimiters, the space, and the hyphen. It will match a space or a hyphen. After that, the expression is used in a reverse way, to get all the words that don't match it i.e. the split words.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A Hyphen is also a special character and will need to be exited as well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it will be removed. For example, the string "lines are hard-coded" will be transformed into a vector of ["lines", "are", "hard", "coded"] by this expression.