Exercise
Household Accounts
Objective
Write a C# program in C# that can store up to 10000 costs and revenues, to create a small domestic accounting system. For each expense (or income), should be allowed to save the following information:
• Date (8 characters: YYYYMMDD format)
• Description of expenditure or revenue
• Category
• Amount (if positive income, negative if an expense)
The program should allow the user to perform the following operations:
1 - Add a new expense (the date should "look right": day 01 to 31 months from 01 to 12 years between 1000 and 3000). The description must not be empty. Needless to validate the other data.
2 - Show all expenses of a certain category (eg, "studies") between two certain dates (eg between "20110101" and "20111231"). Number is displayed, date (format DD / MM / YYYY), description, category in parentheses, and amount to two decimal places, all in the same line, separated by hyphens. At the end of all data show the total amount of data displayed.
3 - Search costs containing a certain text (in the description or category without distinguishing case sensitive). Number is displayed, the date and description (the description is displayed in the sixth truncated blank, if any spaces six or more).
4 - Modify a tab (tab number prompt the user, it will show the previous value of each field and press Enter to not be able to modify any of the data). Should be advised (but not re-order) if the user enters a wrong card number. Needless to validate any data.
5 - Delete some data, from the number that you enter. Should be advised (but not re-order) if you enter an incorrect number. It should show the card to be clear and prompt prior to deletion.
6 - Sort data alphabetically, by date and (if matched) description.
7 - Normalize descriptions: remove trailing spaces, spaces and mirror sites. If a description is all uppercase, will be converted to lowercase (except for the first letter, kept in uppercase).
T-End the use of the application (as we store the information, the data will be lost).
Write Your C# Exercise
C# Exercise Example
using System;
using System.Collections.Generic;
using System.Linq;
namespace HouseholdAccounts
{
class Program
{
// Create a structure to store cost/revenue information
struct AccountEntry
{
public string Date; // Date in YYYYMMDD format
public string Description; // Description of the expense or income
public string Category; // Category of the expense or income
public decimal Amount; // Amount (positive for income, negative for expense)
}
static List accountEntries = new List(); // List to store all account entries
// Method to add a new account entry
static void AddNewEntry()
{
// Ask user for date, description, category, and amount
Console.WriteLine("Enter the date (YYYYMMDD):");
string date = Console.ReadLine();
// Validate the date format (it should be YYYYMMDD, a valid date)
DateTime validDate;
while (!DateTime.TryParseExact(date, "yyyyMMdd", null, System.Globalization.DateTimeStyles.None, out validDate))
{
Console.WriteLine("Invalid date. Please enter in the format YYYYMMDD:");
date = Console.ReadLine();
}
// Ask for description
Console.WriteLine("Enter description:");
string description = Console.ReadLine();
while (string.IsNullOrEmpty(description))
{
Console.WriteLine("Description cannot be empty. Please enter a description:");
description = Console.ReadLine();
}
// Ask for category
Console.WriteLine("Enter category:");
string category = Console.ReadLine();
// Ask for amount
Console.WriteLine("Enter amount (positive for income, negative for expense):");
decimal amount = Convert.ToDecimal(Console.ReadLine());
// Create a new account entry and add it to the list
AccountEntry entry = new AccountEntry
{
Date = date,
Description = description,
Category = category,
Amount = amount
};
accountEntries.Add(entry);
}
// Method to show all expenses of a certain category between two dates
static void ShowExpensesByCategory()
{
Console.WriteLine("Enter start date (YYYYMMDD):");
string startDate = Console.ReadLine();
Console.WriteLine("Enter end date (YYYYMMDD):");
string endDate = Console.ReadLine();
// Filter the list by date range and category
var filteredEntries = accountEntries.Where(e =>
string.Compare(e.Date, startDate) >= 0 && string.Compare(e.Date, endDate) <= 0).ToList();
Console.WriteLine("Enter category:");
string category = Console.ReadLine();
// Filter by category
filteredEntries = filteredEntries.Where(e => e.Category.Equals(category, StringComparison.OrdinalIgnoreCase)).ToList();
// Display the filtered records
decimal totalAmount = 0;
int count = 1;
foreach (var entry in filteredEntries)
{
// Format and display each entry
Console.WriteLine($"{count} - {entry.Date.Substring(6, 2)}/{entry.Date.Substring(4, 2)}/{entry.Date.Substring(0, 4)} - {entry.Description} - ({entry.Category}) - {entry.Amount:F2}");
totalAmount += entry.Amount;
count++;
}
Console.WriteLine($"Total amount: {totalAmount:F2}");
}
// Method to search for costs containing certain text in the description or category
static void SearchCostsByText()
{
Console.WriteLine("Enter text to search:");
string searchText = Console.ReadLine().ToLower();
// Find entries that match the search text in either description or category (case insensitive)
var searchResults = accountEntries.Where(e =>
e.Description.ToLower().Contains(searchText) || e.Category.ToLower().Contains(searchText)).ToList();
if (searchResults.Count == 0)
{
Console.WriteLine("No records found.");
}
else
{
int count = 1;
foreach (var entry in searchResults)
{
// Display the result with description truncated if necessary
string description = entry.Description.Length > 50 ? entry.Description.Substring(0, 50) + "..." : entry.Description;
Console.WriteLine($"{count} - {entry.Date.Substring(6, 2)}/{entry.Date.Substring(4, 2)}/{entry.Date.Substring(0, 4)} - {description}");
count++;
}
}
}
// Method to modify a record
static void ModifyRecord()
{
Console.WriteLine("Enter the record number to modify:");
int recordNumber = Convert.ToInt32(Console.ReadLine()) - 1;
if (recordNumber < 0 || recordNumber >= accountEntries.Count)
{
Console.WriteLine("Invalid record number.");
return;
}
// Show current values for modification
AccountEntry entry = accountEntries[recordNumber];
Console.WriteLine($"Current values: Date: {entry.Date}, Description: {entry.Description}, Category: {entry.Category}, Amount: {entry.Amount}");
// Modify each field
Console.WriteLine("Enter new date (or press Enter to keep current):");
string newDate = Console.ReadLine();
if (!string.IsNullOrEmpty(newDate)) entry.Date = newDate;
Console.WriteLine("Enter new description (or press Enter to keep current):");
string newDescription = Console.ReadLine();
if (!string.IsNullOrEmpty(newDescription)) entry.Description = newDescription;
Console.WriteLine("Enter new category (or press Enter to keep current):");
string newCategory = Console.ReadLine();
if (!string.IsNullOrEmpty(newCategory)) entry.Category = newCategory;
Console.WriteLine("Enter new amount (or press Enter to keep current):");
string newAmount = Console.ReadLine();
if (!string.IsNullOrEmpty(newAmount)) entry.Amount = Convert.ToDecimal(newAmount);
// Save the modified entry
accountEntries[recordNumber] = entry;
}
// Method to delete some data
static void DeleteData()
{
Console.WriteLine("Enter start record number to delete:");
int startRecord = Convert.ToInt32(Console.ReadLine()) - 1;
Console.WriteLine("Enter end record number to delete:");
int endRecord = Convert.ToInt32(Console.ReadLine()) - 1;
if (startRecord < 0 || endRecord >= accountEntries.Count || startRecord > endRecord)
{
Console.WriteLine("Invalid record numbers.");
return;
}
// Confirm deletion of records
for (int i = startRecord; i <= endRecord; i++)
{
Console.WriteLine($"Are you sure you want to delete record {i + 1}? (Y/N)");
string confirmation = Console.ReadLine().ToUpper();
if (confirmation == "Y")
{
accountEntries.RemoveAt(i);
i--; // Adjust for removed entry
}
}
}
// Method to sort the data alphabetically by date and description
static void SortData()
{
var sortedEntries = accountEntries.OrderBy(e => e.Date).ThenBy(e => e.Description).ToList();
// Display sorted entries
int count = 1;
foreach (var entry in sortedEntries)
{
Console.WriteLine($"{count} - {entry.Date.Substring(6, 2)}/{entry.Date.Substring(4, 2)}/{entry.Date.Substring(0, 4)} - {entry.Description} - ({entry.Category}) - {entry.Amount:F2}");
count++;
}
}
// Method to normalize descriptions
static void NormalizeDescriptions()
{
foreach (var entry in accountEntries)
{
string normalizedDescription = entry.Description.Trim();
if (normalizedDescription.ToUpper() == normalizedDescription) // If the description is all uppercase
{
normalizedDescription = char.ToUpper(normalizedDescription[0]) + normalizedDescription.Substring(1).ToLower();
}
// Update the description in the entry
entry.Description = normalizedDescription;
}
}
// Main method to run the application
static void Main(string[] args)
{
bool running = true;
while (running)
{
Console.WriteLine("\nChoose an option:");
Console.WriteLine("1 - Add new expense");
Console.WriteLine("2 - Show expenses by category");
Console.WriteLine("3 - Search costs by text");
Console.WriteLine("4 - Modify record");
Console.WriteLine("5 - Delete data");
Console.WriteLine("6 - Sort data");
Console.WriteLine("7 - Normalize descriptions");
Console.WriteLine("T - End application");
string choice = Console.ReadLine().ToUpper();
switch (choice)
{
case "1":
AddNewEntry();
break;
case "2":
ShowExpensesByCategory();
break;
case "3":
SearchCostsByText();
break;
case "4":
ModifyRecord();
break;
case "5":
DeleteData();
break;
case "6":
SortData();
break;
case "7":
NormalizeDescriptions();
break;
case "T":
running = false;
break;
default:
Console.WriteLine("Invalid option.");
break;
}
}
}
}
}