using System; using System.IO; namespace K2 { public interface IBetween { /// /// Indicates whether the value of the certain property of the current instance is in /// [, ] range including range marginal values. /// should always precede in default sort order. /// /// The starting value of the range /// The ending value of the range /// true if the value of the current object property is in range; otherwise, /// false. bool MutuallyInclusiveBetween(T from, T to); /// /// Indicates whether the value of the certain property of the current instance is in /// [, ] range excluding range marginal values. /// should always precede in default sort order. /// /// The starting value of the range /// The ending value of the range /// true if the value of the current object property is in range; otherwise, /// false. bool MutuallyExclusiveBetween(T from, T to); } /// /// Provides generic container where the data are stored in the linked list. /// /// The type of the data to be stored in the list. Data /// class should implement some interfaces. public class LinkList where T: IComparable { class Node { public T Data { get; set; } public Node Next { get; set; } public Node(T data, Node next) { Data = data; Next = next; } } /// /// All the time should point to the first element of the list. /// private Node begin; /// /// All the time should point to the last element of the list. /// private Node end; /// /// Shouldn't be used in any other methods except Begin(), Next(), Exist() and Get(). /// private Node current; /// /// Initializes a new instance of the LinkList class with empty list. /// public LinkList() { begin = current = end = null; } /// /// One of four interface methods devoted to loop through a list and get value stored in it. /// Method should be used to move internal pointer to the first element of the list. /// public void Begin() { current = begin; } /// /// One of four interface methods devoted to loop through a list and get value stored in it. /// Method should be used to move internal pointer to the next element of the list. /// public void Next() { current = current.Next; } /// /// One of four interface methods devoted to loop through a list and get value stored in it. /// Method should be used to check whether the internal pointer points to the element of the list. /// /// true, if the internal pointer points to some element of the list; otherwise, /// false. public bool Exist() { return current != null; } /// /// One of four interface methods devoted to loop through a list and get value stored in it. /// Method should be used to get the value stored in the node pointed by the internal pointer. /// /// the value of the element that is pointed by the internal pointer. public T Get() { return current.Data; } /// /// Method appends new node to the end of the list and saves in it /// passed by the parameter. /// /// The data to be stored in the list. public void Add(T data) { var node = new Node(data, null); if (begin == null) { begin = node; end = node; } else { end.Next = node; end = node; } } /// /// Method sorts data in the list. The data object class should implement IComparable /// interface though defining sort order. /// public void Sort() { for (Node nodeA = begin; nodeA != null; nodeA = nodeA.Next) { if (nodeA.Next == null) continue; for (Node nodeB = nodeA.Next; nodeB != null; nodeB = nodeB.Next) { if (nodeA.Data.CompareTo(nodeB.Data) < 0) { T tmp = nodeA.Data; nodeA.Data = nodeB.Data; nodeB.Data = tmp; } } } } } /// /// Provides properties and interface implementations for the storing and manipulating of cars data. /// public class Car : IComparable, IBetween, IBetween { public string Manufacturer { get; set; } public string Model { get; set; } public double Price { get; set; } public Car(string manufacturer, string model, double price) { Manufacturer = manufacturer; Model = model; Price = price; } /// /// Compares the current instance with another object of the same type and returns an integer /// that indicates whether the current instance precedes, follows, or occurs in the same /// position in the sort order as the other object. /// /// An object to compare with this instance. /// A value that indicates the relative order of the objects being compared.The /// return value has these meanings: -1 when this instance precedes other in the sort order; /// 0 when this instance occurs in the same position in the sort order as other; /// 1 when this instance follows other in the sort order. public int CompareTo(Car other) { if (Price < other.Price) { return -1; } else if (Price == other.Price) { return -Model.CompareTo(other.Model); } else { return 1; } } public bool MutuallyInclusiveBetween(double from, double to) { return from <= Price && Price <= to; } public bool MutuallyExclusiveBetween(double from, double to) { return from < Price && Price < to; } public bool MutuallyInclusiveBetween(string from, string to) { return Manufacturer.CompareTo(from) <= 0 && Manufacturer.CompareTo(to) >= 0; } public bool MutuallyExclusiveBetween(string from, string to) { return Manufacturer.CompareTo(from) < 0 && Manufacturer.CompareTo(to) > 0; } } public static class InOut { /// /// Creates the list containing data read from the text file. /// /// The name of the text file /// List with data from file public static LinkList ReadFromFile(string fileName) { var cars = new LinkList(); foreach (var line in File.ReadAllLines(fileName)) { string[] parts = line.Split(';'); string manufacturer = parts[0].Trim(); string model = parts[1].Trim(); double price = double.Parse(parts[2].Trim()); cars.Add(new Car(manufacturer, model, price)); } return cars; } /// /// Appends the table, built from data contained in the list and preceded by the header, /// to the end of the text file. /// /// The name of the text file /// The header of the table /// The list from which the table to be formed public static void PrintToFile(string fileName, string header, LinkList list) { using (var writer = new StreamWriter(fileName, true)) { writer.WriteLine(new string('-', 53)); writer.WriteLine("| {0, -49} |", header); writer.WriteLine(new string('-', 53)); // Klausimas: Ar GRIEŽTAI negalima kurtis savo pagalbinių funkcijų? // Nes šitoje situacijoje žemiau labai praverstų tiesiog susikurti `IsEmpty` metodą. // Kartu prie to pačio, man labai nepatinka `Begin`, `Exist` ir `Next`, tai koks `IEnumerable` // manau yra žymiai geresnis sprendimas, kad kaip sukti ciklą per listą. list.Begin(); if (list.Exist()) { writer.WriteLine("| {0,-20} | {1,-15} | {2,8} |", "Gamintojas", "Modelis", "Kaina"); writer.WriteLine(new string('-', 53)); for (list.Begin(); list.Exist(); list.Next()) { var car = list.Get(); writer.WriteLine("| {0,-20} | {1,-15} | {2,8:f2} |", car.Manufacturer, car.Model, car.Price); } } else { writer.WriteLine("| {0, -49} |", "Nėra"); } writer.WriteLine(new string('-', 53)); writer.WriteLine(); } } } public static class Task { /// /// The method finds the biggest price value in the given list. /// /// The data list to be searched. /// The biggest price value. public static double MaxPrice(LinkList list) { double maxPrice = -1; for (list.Begin(); list.Exist(); list.Next()) { var car = list.Get(); maxPrice = Math.Max(maxPrice, car.Price); } return maxPrice; } /// /// Filters data from the source list that meets filtering criteria and writes them /// into the new list. /// /// The type of the data objects stored in the list /// The type of criteria /// The source list from which the result would be created /// Lower bound of the interval /// Upper bound of the interval /// The list that contains filtered data public static LinkList Filter(LinkList source, TCriteria from, TCriteria to) where TData : IComparable, IBetween { var filtered = new LinkList(); for (source.Begin(); source.Exist(); source.Next()) { var item = source.Get(); if (item.MutuallyInclusiveBetween(from, to)) { filtered.Add(item); } } return filtered; } } class Program { // Klausimas: Ar reikia kurti testus `LinkList` klasei? static void Main() { string inputFilename = "Duomenys.txt"; string outputFilename = "Rezultatai.txt"; File.Delete(outputFilename); Console.Write("Įveskite pirmą gamintoją: "); string manufacturer1 = Console.ReadLine(); Console.Write("Įveskite antrą gamintoją: "); string manufacturer2 = Console.ReadLine(); var cars1 = InOut.ReadFromFile(inputFilename); InOut.PrintToFile(outputFilename, "Pradinės mašinos", cars1); var cars2 = Task.Filter(cars1, manufacturer1, manufacturer1); var cars3 = Task.Filter(cars1, manufacturer2, manufacturer2); InOut.PrintToFile(outputFilename, string.Format("Mašinos pagal gamintoją '{0}'", manufacturer1), cars2); InOut.PrintToFile(outputFilename, string.Format("Mašinos pagal gamintoją '{0}'", manufacturer2), cars3); var maxPrice = Task.MaxPrice(cars1); var cars4 = Task.Filter(cars2, maxPrice * 0.75, maxPrice); var cars5 = Task.Filter(cars3, maxPrice * 0.75, maxPrice); cars4.Sort(); cars5.Sort(); InOut.PrintToFile(outputFilename, string.Format("Brangios mašinos pagal gamintoją '{0}'", manufacturer1), cars4); InOut.PrintToFile(outputFilename, string.Format("Brangios mašinos pagal gamintoją '{0}'", manufacturer2), cars5); // Klausimas: Ar galima įdėti išdemą į failą maine? // Taip, žinau per LD darbus negalima tai daryti. Bet K2 apraše // parašyta, kad negalima pridėti naujų metodų ar keisti egzistuojančių // kamienus. // Bet reikalaujama išvesti surastą didžiausią kainą į failo galą // su paaiškinamu tekstu. // Paradoksas ¯\_(ツ)_/¯ using (var writer = new StreamWriter(outputFilename, true)) { writer.WriteLine("Didžiausia mašinos kaina: {0:f2}", maxPrice); } // Klausimas: Kas sugalvojo šitą užduotį?!?!?! // Kodėl tą inteface reikia panaudoti 2 kartus ant `Car` // klasės, kad būtų galima patikrinti skirtingus laukus?! Atrodo, kad specialiai // sąlyga buvo 'priplakta' su daug nereikalingų dalykų. // Dar reikėjo panaudoti `Task.Filter` du kartus su skirtingais interface kad tiktais // filtruoti paprastą dalyką ir galų gale gavosi, kad reikia aplamai turėti daugiau kodo // kad pasiekti tą patį rezultatą. Ir dar lieka `MutuallyExclusiveBetween` metodai nepanaudoti. // // Ką galiu pasakyti tai, kad man labai nepatiko šita užduotis. } } }