c# Return string of Customer name - c#

I am new to C# and trying to solve some simple tasks and I find my self stuck in a methode that is supposed to get the name of the next customer from right on the list:
The task:
I am given is a directed graph of Customers, where one Customer has exactly one reference to the next Customer or null if it is the last Customer. An example of such a graph can be seen in the diagram below.
Given such a graph, I need to find the customer int numberFromRight nodes from right in the graph by implementing the IFinder interface.
Here is the code I have been working on
class Program
{
static void Main(string[] args)
{
var currentCustomer = Customers
.Create("Kim")
.Previous("Hans")
.Previous("Ole")
.Previous("Peter");
while (currentCustomer != null)
{
if (currentCustomer.Next != null)
Console.Write(currentCustomer.Person + " -> ");
else
Console.WriteLine(currentCustomer.Person);
currentCustomer = currentCustomer.Next;
}
Console.ReadLine();
}
}
Customer class
public class Customers
{
private Customers(Customers next, string person)
{
Next = next;
Person = person;
}
public Customers Next { get; }
public string Person { get; }
public Customers Previous(string person)
{
return new Customers(this, person);
}
public static Customers Create(string person)
{
return new Customers(null, person);
}
}
IFinder interface
public interface IFinder
{
string FromRight(Customers customers, int numberFromRight);
}
I want to write my answer in this method and in example is in the graph below the result for FromRight(peter, 3) is Ole.:
public class Finder : IFinder
{
public string FromRight(Customers customers, int numberFromRight)
{
return name;
}
}

Simple solution without recursion:
public class Finder : IFinder
{
public string FromRight(Customers customers, int numberFromRight)
{
return Unwind(customers).Reverse().Skip(numberFromRight - 1).FirstOrDefault()?.Person;
}
private static IEnumerable<Customers> Unwind(Customers customers)
{
while (customers != null)
{
yield return customers;
customers = customers.Next;
}
}
}

The task: I am given is a directed graph of Customers, where one Customer has exactly one reference to the next Customer or null if it is the last Customer.
So basically what you have in memory is a linked list. While they have some advantages, they are pretty rarely used outside of tree structures exactly because they are a pain to itterate or random access over.
I want to write my answer in this methode and in example is in the
graph below the result for FromRight(peter, 3) is Ole.:
This is recursion, with the number being the recursion depth. Something like this:
public string FromRight(Customers customers, int numberFromRight)
{
if(numberFromRight <= 0)
return customers.Name;
else
return FromRight(customer.Next, (numberFromRight-1));
}
I might have a off-by-one error in this. But those buggers are everywhere. And if forget the null check of course. But it should get you into the right direction at least.

You haven't really showed us what you have tried so far here, just giving us the assignment.
So here's the theorical answer :
Use recursion with the following :
if the next customer doesn't exist, you're at the end of the list, therefore you can return a value straight ahead.
if the next customer does exist, then the answer is the next customer's answer plus one.

Related

(C#) Access/Modify Objects in a List

New here, I've been learning c# for about a month.
Anyway, I've been searching StackOverflow for a couple of days now and couldn't find a specific answer to my problem...
//Here's my Class
public class Guy
{
public static int ID { get; set; }
public static int LifeExpectancy { get; set; }
public static bool Living { get; set; }
public Guy(int id, int lifeExpectancy, bool living)
{
ID = id;
LifeExpectancy = lifeExpectancy;
Living = living;
}
}
What I'm trying to do is create a specific number of "someGuy" objects to then put them into a public list using this method...
public static List<Guy> Guys = new List<Guy>();
public static void makeSomeGuys(int howManyGuys)
{
for (int i = 0, i <= howManyGuys; i++)
{
int id = i;
int lifeExpectancy = 80;
bool alive = true;
Guys.Add(New Guy(id, lifeExpectancy, alive));
Console.WriteLine("Made a new Guy {0}", id);
}
return;
}
Questions in order of importance:
How do I access a specific object as well as its parameters? (Accessing from the list "Guys".)
How do I access an object from this list in another class? (Not that I absolutely need to, I'm curious)
Can I search for an object in a list by using its parameters? (As opposed to doing something like... humanPopulation[number])
Should I create a new list for objects that have had their parameters modified? (As opposed to leaving it in the original list)
Is it possible to remove items from a list? (Just in general, is that a thing people do? if so, why?)
I really only need the first question answered. The rest of them are just a bonus. Thanks!
First you need to remove the static modifier from the properties of the Guy class, i.e.:
public int ID { get; set; }
public int LifeExpectancy { get; set; }
public bool Living { get; set; }
because static causes the property to be an attribute of the class itself, rather than the instances of the class (the individual 'guys').
To access life expectancy of the first guy (the zeroth):
Console.WriteLine(Guys[0].LifeExpectancy);
To access life expectancy of the fifth guy:
Console.WriteLine(Guys[4].LifeExpectancy);
using System;
using System.Collections.Generic;
using System.Linq;
namespace test
{
public class Guy
{
private int m_ID;
private int m_LifeExpectancy;
private bool m_Living;
public int ID
{
get { return m_ID; }
set { m_ID = value; }
}
public int LifeExpectancy
{
get { return m_LifeExpectancy; }
set { m_LifeExpectancy = value; }
}
public bool Living
{
get { return m_Living; }
set { m_Living = value; }
}
public Guy(int id, int lifeExpectancy, bool living)
{
ID = id;
LifeExpectancy = lifeExpectancy;
Living = living;
}
}
public class MyFactory
{
public IList<Guy> MakeSomeGuys(int howManyGuys)
{
IList<Guy> localGuys = new List<Guy>();
for (int i = 0; i <= howManyGuys; i++)
{
int id = i;
int lifeExpectancy = 80;
bool alive = true;
localGuys.Add(new Guy(id, lifeExpectancy, alive));
Console.WriteLine("Made a new Guy {0}", id);
}
return localGuys;
}
}
public class program
{
public void Main()
{
MyFactory mf = new MyFactory();
IList<Guy> guys = mf.MakeSomeGuys(5);
//How do I access a specific object as well as its parameters? (Accessing from the list "Guys".)
int GetFirstGuyId = guys.FirstOrDefault().ID; //LEARN LINQ
//How do I access an object from this list in another class? (Not that I absolutely need to, I'm curious)
//you need to learn about object oriented encapsulation for better understanding.
//Can I search for an object in a list by using its parameters? (As opposed to doing something like...humanPopulation[number])
Guy guyById = guys.Where(g => g.ID == 5).FirstOrDefault(); // returns the first match (need to learn lambda expression)
//Should I create a new list for objects that have had their parameters modified? (As opposed to leaving it in the original list)
// you need to learn about passing values by value / reference (by reference you already changing the original!).
//Is it possible to remove items from a list? (Just in general, is that a thing people do? if so, why?)
//yes
guys.Remove(guyById);
}
}
}
You're likely new to C# and OO programming, so I've included some good links in this answer.
Regarding question 1 only:
Firstly, your Guy class properties aren't properly encapsulated. Make sure you properly scope the ID, LifeExpectancy and Living properties like shown in this article.
If you'd like to access a specific item, that is, a Guy with a particular ID, you'd be better off using an associative container like Dictionary.
If you're happy with the List container, you need to use the Find method on Guys as shown in the example at the link. You'll notice the term Predicate in the documentation, this link will elaborate.

C# Match User Inputs to Array

I'm writing some code where I have some information about customers stored in an array called members (id, initials). I then ask the user for their id and initials and match the inputs to the stored information from array members. If they match I move on. However I get an error in my coding: "an object reference is required to access non-static field method or property". The error comes from the if statements. Any suggestions on how to correct this issue?
Some background info: I have two classes, one called Customer and one called Menu. The Menu is the main class while Customer is the class I reference from.
This is from my Menu class:
int L = 0;
string I = "";
Customer[] members = new Customer[2];
members[0] = new Customer(3242, "JS");
members[1] = new Customer(7654, "BJ");
Console.Write("\nWhat is your Loyalty ID #: ");
L =Convert.ToInt32(Console.ReadLine());
Console.Write("\nWhat is your first and last name initials: ");
I = Console.ReadLine();
if (L==Customer.GetId())
{
if (I == Customer.GetInitials())
{
Console.WriteLine("It matches");
}
}
else
{
Console.WriteLine("NO match");
}
Console.ReadKey();
}
}
}
This from my Customer class
private int id;
private string initials;
public Customer ()
{
}
public Customer(int id, string initials)
{
SetId(id);
SetInitials(initials);
}
public int GetId()
{
return id;
}
public void SetId(int newId)
{
id = newId;
}
public string GetInitials()
{
return initials;
}
public void SetInitials(string newInitials)
{
initials = newInitials;
}
The error means exactly what it says. You can't access the GetId() function of Customer by calling Customer.GetId() because GetId() only works on an instance of Customer, not directly through the Customer class.
Customer.GetId(); //this doesn't work
Customer myCustomer=new Customer(); myCustomer.GetId(); //this works
To check the user's input against your array of inputs, you need to iterate through the array (or alternatively, use Linq).
I'm going to use a generic list, because there's not really a good reason to use arrays in most cases.
List<Customer> customers=new List<Customer>();
Customers.Add();//call this to add to the customers list.
foreach(var c in customers)
{
if(c.GetId() == inputId)
{
//match!
}
else
{
//not a match
}
}
You can also improve your Customer class by using properties, or auto properties (which doesn't need a backing field). Here's an auto property example:
public string Id {get; set;} // notice there's no backing field?
Using the above auto property syntax would allow you do to this:
var customer = new Customer();
string id = customer.Id; // notice there's no parentheses?
Properties and auto properties allow for a cleaner syntax than having to write Java-style separate getters/setters.

Sort a list by an element of a class

first of all congrats for the web, this is my first question but I have found a lot of answer before here.
Here my problem: I have to take some data from an excel file and print them off in a file. Until here everything is ok. But depending on the order of the file list, I take the data in one or another order. My proposal is after all the data have been taken from the excel, to sort those data by the date of the bill (one of the elements of the data). I am describing my classes below.
I have my Bill class:
class Bill
{
private string billNumber;
private string billDate;
private DateTime date;
private string from;
private string to;
private string billCost;
private string power1;
private string power2;
private string power3;
private string power4;
private string power5;
private string power6;
private string contractNumber;
}
And this is my Contract Class:
class Contract
{
private List<Bill> billList;
private Dictionary<double, Bill> billsDictionary;
private double contractNumber;
}
After in my program I have a List<Contract>.
I would like to sort the List<Bill> of the Contract class by the date, to be able to print the bill in the correct order, but I have not been able to find any solution to order them.
Thanks in advance.
Greetings.
There are two solutions. First you need to expose property that can be used to sort.
public class Bill
{
// ... rest of your code
public DateTime Date
{
get
{
return this.date;
}
}
}
1) You can use List's Sort with passed comparer (msdn):
public class Comp : IComparer<Bill>
{
public int Compare(Bill x, Bill y)
{
// remember to handle null values first (x or y or both are nulls)
return x.Date.CompareTo(y.Date);
}
}
then:
billList.Sort(new Comp());
Keep in mind: if you declare Comp as nested class of Bill you won't have to add property Date. You will be able to see private fields of Bill and use it for comparsion..
2) You can use linq (it creates new instance of List):
billList = billList.OrderBy(bill => bill.Date).ToList();
You should be able to do that using linq like q = q.OrderBy(a => a.ColumnName) but you may want to check the access modifiers of your properties, being private you won't be able to access them from the outside.
Here's a simple example on ordering with Linq:
class Pet
{
public string Name { get; set; }
public int Age { get; set; }
}
public static void OrderByEx1()
{
Pet[] pets = { new Pet { Name="Barley", Age=8 },
new Pet { Name="Boots", Age=4 },
new Pet { Name="Whiskers", Age=1 } };
IEnumerable<Pet> query = pets.OrderBy(pet => pet.Age);
foreach (Pet pet in query)
{
Console.WriteLine("{0} - {1}", pet.Name, pet.Age);
}
}
/*
This code produces the following output:
Whiskers - 1
Boots - 4
Barley - 8
*/
Notice how the properties of the class are public so you can access them from anywhere in the code.
More info on sorting can be found here.

How should I use properties and what should be structure of my class for using indexers across multiple classes

I need help as to how do I go about the structure of classes. How do I use Indexers? I want to have something like
Company.Employees[empId].Employee["Designation"].Salary
To be more specific something like
Grid.Rows[rowIndex].Columns["CurrentColumnName"].Width
Add a method like
public string this[string s]
{
get{
if(s == ...)
return this.property;
}
}
Yet, this seems to be more a Situation for Collections, but
see here for a complete example.
Actually indexers are used to get element by index, and your EmpId is not a good candidate for indexing as these may be compost or non sequential.
If you still want to use it here is the code. It will mimic as Indexer but its modified version.
class Employee
{
public int EmpId { get; set; }
public float Salary { get; set; }
public string Designation { get; set; }
}
class Employees
{
List<Employee> EmpList = new List<Employee>();
public Employee this[int empId]
{
get
{
return EmpList.Find(x => x.EmpId == empId);
}
}
}
I would rather have a method because I can make it generic.
public T GetPropertyValue<T>(string property)
{
var propertyInfo = GetType().GetProperty(property);
return (T)propertyInfo.GetValue(this, null);
}
var emp = employee.GetPropertyValue<Employee>("Designation");
var salary = emp.Salary;
That said... Be careful for having so many dot notations. When you get that NullReferenceException on your line in a log file, it is very difficult to find out what exactly was null. So rather break things up a bit and have more lines then you have less trouble of resolving bugs.

Creating a simple NSOutlineView datasource with MonoMac

I cant seem to figure out how to create a simple NSOutlineView with 2 columns, and a datastructure that is more than 1 level deep (a hierachy).
I've been researching this for days, and all I can find is Objective C examples, which I really can't use for anything.
I understand there are different patterns for doing this, one being the DataSource pattern. I tried creating a class that inherited from NSOutlineViewDataSource, however thats all I got, I have no clue on what I should do next!
Lets say I would like to display the following class in my NSOutlineView:
public class Person
{
public string Name {get;set;} // First column
public int Age {get;set} // Second column
public List<Person> Children {get;set} // Children
}
What would be the most trivial approach to accomplishing this?
Brace yourselves... A level-independant NSOutlineView in MonoMac!
After hundreds of google searches, and looking through ObjC as well as C# code, I finally figured out how to do it! I will post my solution here, in case someone else needs it.
This may or may not be the best way to do it, but it works for me.
Step 1: In Interface Builder, add an NSOutlineView. Add 2 columns to it, and set their Identifier to colName, and colAge.
Also, while you're at it, add a button to your form.
Step 2: Create an outlet for the NSOutlineView - I called mine lvMain because I come from a VCL background. Also, create an action for your button (this will be the onClick handler).
Step 3: Save your XIB file, and return to Mono - it will update your project file. Now, we want to create the model we wish to use for our view.
For this example, I will use a simple Person object:
public class Person:NSObject
{
public string Name {
get;
set;
}
public int Age {
get;
set;
}
public List<Person> Children {
get;
set;
}
public Person (string name, int age)
{
Name = name;
Age = age;
Children = new List<Person>();
}
}
Nothing overly complicated there.
Step 4: Create the datasource. For this example, this is what I made:
public class MyDataSource:NSOutlineViewDataSource
{
/// The list of persons (top level)
public List<Person> Persons {
get;
set;
}
// Constructor
public MyDataSource()
{
// Create the Persons list
Persons = new List<Person>();
}
public override int GetChildrenCount (NSOutlineView outlineView, NSObject item)
{
// If the item is not null, return the child count of our item
if(item != null)
return (item as Person).Children.Count;
// Its null, that means its asking for our root element count.
return Persons.Count();
}
public override NSObject GetObjectValue (NSOutlineView outlineView, NSTableColumn forTableColumn, NSObject byItem)
{
// Is it null? (It really shouldnt be...)
if (byItem != null) {
// Jackpot, typecast to our Person object
var p = ((Person)byItem);
// Get the table column identifier
var ident = forTableColumn.Identifier.ToString();
// We return the appropriate information for each column
if (ident == "colName") {
return (NSString)p.Name;
}
if (ident == "colAge") {
return (NSString)p.Age.ToString();
}
}
// Oh well.. errors dont have to be THAT depressing..
return (NSString)"Not enough jQuery";
}
public override NSObject GetChild (NSOutlineView outlineView, int childIndex, NSObject ofItem)
{
// If the item is null, it's asking for a root element. I had serious trouble figuring this out...
if(ofItem == null)
return Persons[childIndex];
// Return the child its asking for.
return (NSObject)((ofItem as Person).Children[childIndex]);
}
public override bool ItemExpandable (NSOutlineView outlineView, NSObject item)
{
// Straight forward - it wants to know if its expandable.
if(item == null)
return false;
return (item as Person).Children.Count > 0;
}
}
Step 5 - The best step: Bind the datasource and add dummy data! We also wanna refresh our view each time we add a new element. This can probably be optimized, but I'm still in the "Oh my god its working" zone, so I currently don't care.
// Our Click Action
partial void btnClick (NSObject sender)
{
var p = new Person("John Doe",18);
p.Children.Add(new Person("Jane Doe",10));
var ds = lvMain.DataSource as MyDataSource;
ds.Persons.Add(p);
lvMain.ReloadData();
}
public override void AwakeFromNib ()
{
base.AwakeFromNib ();
lvMain.DataSource = new MyDataSource();
}
I hope this information can help the troubled souls of the MonoMac newcomers like myself.
It took me a little while to track this down, but Xamarin has an example of how to do this Here

Categories