patterncppMinor
Calculate Suitability Score program
Viewed 0 times
suitabilityprogramcalculatescore
Problem
I am a beginner in C++ and learning from textbook. I find it hard to jump into oops concepts as I have used C a lot. Here is an interview question I came across:
Problem Statement
Our marketing department has just negotiated a deal with several local merchants that will allow us to offer exclusive discounts on various products to our top customers every day. The catch is that we can only offer each product to one customer and we may only offer one product to each customer.
Each day we will get the list of products that are eligible for these special discounts. We then have to decide which products to offer to which of our customers. Fortunately, our team of highly skilled statisticians has developed an amazing mathematical model for determining how likely a given customer is to buy an offered product by calculating what we call the "suitability score" (SS). The top-secret algorithm to calculate the SS between a customer and a product is this:
Your task is to implement a program that assigns each customer a product to be offered in a way that maximizes the combined total SS across all of the chosen offers. Note that there may be a different number of products and customers. You may include code from external libraries as long as you cite the source.
INPUT SAMPLE:
Your program should accept as its only argument a path to a file. Each line in this file is one test case. Each test case will be a comma delimited set of customer names followed by a semicolon and then a comma delimit
Problem Statement
Our marketing department has just negotiated a deal with several local merchants that will allow us to offer exclusive discounts on various products to our top customers every day. The catch is that we can only offer each product to one customer and we may only offer one product to each customer.
Each day we will get the list of products that are eligible for these special discounts. We then have to decide which products to offer to which of our customers. Fortunately, our team of highly skilled statisticians has developed an amazing mathematical model for determining how likely a given customer is to buy an offered product by calculating what we call the "suitability score" (SS). The top-secret algorithm to calculate the SS between a customer and a product is this:
- If the number of letters in the product's name is even then the SS is the number of vowels (a, e, i, o, u, y) in the customer's name multiplied by 1.5.
- If the number of letters in the product's name is odd then the SS is the number of consonants in the customer's name.
- If the number of letters in the product's name shares any common factors (besides 1) with the number of letters in the customer's name then the SS is multiplied by 1.5.
Your task is to implement a program that assigns each customer a product to be offered in a way that maximizes the combined total SS across all of the chosen offers. Note that there may be a different number of products and customers. You may include code from external libraries as long as you cite the source.
INPUT SAMPLE:
Your program should accept as its only argument a path to a file. Each line in this file is one test case. Each test case will be a comma delimited set of customer names followed by a semicolon and then a comma delimit
Solution
Reading a unit test:
Jareau Wade,Rob Eroh,Mahmoud Abdelkader,Wenyi Cai,Justin Van Winkle,Gabriel Sinkin,Aaron Adelson;Batman No. 1,Football - Official Size,Bass Amplifying Headphones,Elephant food - 1024 lbs,Three Wolf One Moon T-shirt,Dom Perignon 2000 Vintage
EDIT 1:
Same thing applies to stripping things
Of course this can be done in a single line with C++11 and lambdas.
Which technique to use is still a matter of debate. If the operation is common (by common I mean easy to understand and you can tell what it does by its name without looking it up) and you think it can be re-used then I would use a functor. If it is a on-off and short i would use a lambda. Everything else will depnd on how easy it is to read in the context.
Edit 2
Copying arrays/vectors to the output:
Can be greatly simplified. using the above techniques.
Here simply printing the string. But by changing std::string here I can modify how the output is printed. Thus encapsulating and changing the printing behavior.
Jareau Wade,Rob Eroh,Mahmoud Abdelkader,Wenyi Cai,Justin Van Winkle,Gabriel Sinkin,Aaron Adelson;Batman No. 1,Football - Official Size,Bass Amplifying Headphones,Elephant food - 1024 lbs,Three Wolf One Moon T-shirt,Dom Perignon 2000 Vintage
// Utility class that reads ',' seprated words from a stream.
// Also automatically converts to std::string when needed.
struct ItemInList
{
std::string itemValue;
operator std::string {return itemValue;}
friend std::istream& operator>>(std::istream& s, ItemInList& value)
{
return std::getline(s, value.itemValue, ',');
}
};
///// STUFF
std::ifstream file();
std::string allCustomers;
std::getline(file, allCustomers, ';'); // Reads upto ';' puts the content into `allCustomers`
std::stringstream allCustomersStr(allCustomers);// Convert the string into a stream
// Iterate over the stream. Copy the values into the vector.
std::vector customerVec(std::istream_iterator(allCustomersStr),
std::istream_iterator());
std::string allProducts;
std::getline(file, allProducts);
std::stringstream allProductsStr(allProducts);
std::vector productVec(std::istream_iterator(allProductsStr),
std::istream_iterator());EDIT 1:
Same thing applies to stripping things
struct Strip
{
// Defining the method `operator()` means that objects of this type
// Can be called like functions.
//
// Strip stripper;
// std::cout << stripper("String with 56686868 Bad char") << "\n";
//
// This is called a functor (a function like object).
std::string operator()(std::string value) const
{
// remove bad characters.
//
return value;
}
// So why do this over a function.
// It turns out this is much easier for the compiler to optimize.
//
// But this technique is really a closure in disguise.
// A closure is a function with captured state. Now this particular
// one does not capture state but by adding some member variables
// you can save information each time it is called and that
// information can be used on subsequent calls.
};
std::transform(std::begin(product_name), std::end(product_name), // Src
std::begin(product_name), // Dst (same as src
Strip()); // Action create strip object.Of course this can be done in a single line with C++11 and lambdas.
std::transform(std::begin(product_name), std::end(product_name), // Src
std::begin(product_name), // Dst (same as src
[](std::string value){
// remove bad characters. The lambda declaration
// Basically creates an anonymous functor
return value; // behind the scenes.
});Which technique to use is still a matter of debate. If the operation is common (by common I mean easy to understand and you can tell what it does by its name without looking it up) and you think it can be re-used then I would use a functor. If it is a on-off and short i would use a lambda. Everything else will depnd on how easy it is to read in the context.
Edit 2
Copying arrays/vectors to the output:
for (int i=0; i<product_list.size();i++){
std::cout << product_list[i] << "\n\n" << std::endl;Can be greatly simplified. using the above techniques.
std::copy(std::begin(product_list), std::end(product_list),
std::ostream_iterator(std::cout, "\n\n\n"));
// ^^^^^^^^^^^Here simply printing the string. But by changing std::string here I can modify how the output is printed. Thus encapsulating and changing the printing behavior.
Code Snippets
// Utility class that reads ',' seprated words from a stream.
// Also automatically converts to std::string when needed.
struct ItemInList
{
std::string itemValue;
operator std::string {return itemValue;}
friend std::istream& operator>>(std::istream& s, ItemInList& value)
{
return std::getline(s, value.itemValue, ',');
}
};
///// STUFF
std::ifstream file(<fileName>);
std::string allCustomers;
std::getline(file, allCustomers, ';'); // Reads upto ';' puts the content into `allCustomers`
std::stringstream allCustomersStr(allCustomers);// Convert the string into a stream
// Iterate over the stream. Copy the values into the vector.
std::vector<std::string> customerVec(std::istream_iterator<ItemInList>(allCustomersStr),
std::istream_iterator<ItemInList>());
std::string allProducts;
std::getline(file, allProducts);
std::stringstream allProductsStr(allProducts);
std::vector<std::string> productVec(std::istream_iterator<ItemInList>(allProductsStr),
std::istream_iterator<ItemInList>());struct Strip
{
// Defining the method `operator()` means that objects of this type
// Can be called like functions.
//
// Strip stripper;
// std::cout << stripper("String with 56686868 Bad char") << "\n";
//
// This is called a functor (a function like object).
std::string operator()(std::string value) const
{
// remove bad characters.
//
return value;
}
// So why do this over a function.
// It turns out this is much easier for the compiler to optimize.
//
// But this technique is really a closure in disguise.
// A closure is a function with captured state. Now this particular
// one does not capture state but by adding some member variables
// you can save information each time it is called and that
// information can be used on subsequent calls.
};
std::transform(std::begin(product_name), std::end(product_name), // Src
std::begin(product_name), // Dst (same as src
Strip()); // Action create strip object.std::transform(std::begin(product_name), std::end(product_name), // Src
std::begin(product_name), // Dst (same as src
[](std::string value){
// remove bad characters. The lambda declaration
// Basically creates an anonymous functor
return value; // behind the scenes.
});for (int i=0; i<product_list.size();i++){
std::cout << product_list[i] << "\n\n" << std::endl;std::copy(std::begin(product_list), std::end(product_list),
std::ostream_iterator<std::string>(std::cout, "\n\n\n"));
// ^^^^^^^^^^^Context
StackExchange Code Review Q#45351, answer score: 3
Revisions (0)
No revisions yet.