Matching specific entries in lists - c#

Currently I'm trying to write a CSV exporter utility for work to help speed up the process of creating work orders for our supervisors. On paper it's quite a simple concept, import the CSV containing our part information and our current production requirements. The columns of the CSV are being split into separate lists. I'm trying to create a button that will allow the user to automatically set the quantity based on the part number.
The way I'm currently thinking about doing this is by grabbing the specific entry on the list's 'spot' (can't think of a better term).
Example:
Dinosaur List
1. T-Rex
2. Triceratops
3. Allosaurus
Diet List
1. Carnivore
2. Herbivore
3. Carnivore
If my user selected Allosaurus, I would want a value returned of 3, and then I would use that to grab the right entry from my second list, in this case, Carnivore.
I'm not sure exactly how I would go about doing this, and any help or direction would be greatly appreciated.

You should really use Object-Oriented programming in this case.
If I were you, I'd declare a class Dinosaur, and make subclasses for each type of dinosaur. In the super class (Dinosaur), put an abstract property of type DinosaurDiet to force subclasses to implement this property. Here's a bit of code to explain what I'm saying:
enum DinosaurDiet //The enumeration for the types of diet
{
Carnivore,
Herbivore
}
abstract class Dinosaur //abstract meaning it can't be instanciated, and only serves as a superclass
{
public abstract DinosaurDiet Diet { get; }
}
class TRex : Dinosaur
{
public override DinosaurDiet Diet { get { return DinosaurDiet.Carnivore; } }
}
class Triceratop : Dinosaur
{
public override DinosaurDiet Diet { get { return DinosaurDiet.Herbivore; } }
}
class Allosaurus : Dinosaur
{
public override DinosaurDiet Diet { get { return DinosaurDiet.Carnivore; } }
}
Once you have all that, you can make a list of them and get them using an index. Here's how:
List<Dinosaur> dinos = new List<Dinosaur>();
dinos.Add(new TRex());
dinos.Add(new Triceratop());
dinos.Add(new Allosaurus());
//Get the 2nd dinosaur from the list (0-based)
int index = 1;
Dinosaur d = dinos[index];
Make sure to test index >= 0 && index < dinos.Count to avoid an exception when trying to get an element at an out-of-bound index.

Related

How to sort a List<> that contains derived class objects, by derived class method

I have a double problem here. I need to sort a List<> that I know contains objects of a derived class to the class that the list was declared to contain originally. AND, I need to sort by the return value from a method in that derived class, which takes a parameter. Keep in mind that I already know the List contains objects all of the derived class type.
I've created some sample code here to demonstrate the question since the real code cannot be shared publicly. Note, I have no control over the base conditions here (i.e. the fact that the List<> collection's declared contents are the parent class and that it contains objects of the derived class, which contains a method that takes an argument and returns the values that I need to sort the collection by). So, I doubt I'd be able to use any suggestion that requires changes there. What I think I need is a way to specify (cast?) what is really in the List so I can access the method defined there. But I'm open to other thoughts for sure. Otherwise I'm left with a traditional bubble sort. Thanks.
public class Component
{
public int X;
public int Y;
}
public class ComponentList : List<Component>
{
// Other members that deal with Components, generically
}
public class Fence : Component
{
public int Distance(int FromX, int FromY)
{
int returnValue = 0;
// Caluclate distance...
return returnValue;
}
}
public class Yard : Component
{
// Yada yada yada
}
public class MyCode
{
public List<Component> MyFences;
public MyCode(List<Component> Fences, int FromX, int FromY)
{
// Sort the fences by their distance from specified X,Y
Fences.Sort((A as Fence, B as Fence) => A.Distance(FromX, FromY).CompareTo(B.Distance(FromX, FromY)));
// Or
List<Fence> sortedFences = MyFences.OrderBy(A => A.Distance(FromX, FromY)).ToList();
// Or ???
}
}
Use the Enumerable.Cast<Fence> extension method to transform your IEnumerable<Component> to IEnumerable<Fence>. Then I'd use your second approach (the OrderBy approach) to sort it, but that's my preference.
List<Fence> sortedFences = MyFences.Cast<Fence>().OrderBy(A => A.Distance(FromX, FromY)).ToList();
This approach will throw if there is an object in MyFences that can't be cast to Fence. If you expect that the code should only be passed Fences, this might be what you want. If, instead, you want to skip over non-Fence members, you can use:
List<Fence> sortedFences = MyFences.OfType<Fence>().OrderBy(A => A.Distance(FromX, FromY)).ToList();

Read only list of lists c#

In general terms, a program I'm making involves storing a small number of entries (probably less than 30 at any given time) which can be categorized. I want to allow these entries to be seen but not altered from outside the class using them. I made a class called Entry which could be modified and another called ReadOnlyEntry which is a wrapper for an Entry object. The easiest way to organize these Entry objects it seems is to create a List<List<Entry>>, where each List<Entry> is a category. But then exposing that data in a readonly way became messy and complicated. I realized I would have to have one object of each of the following types:
List<List<Entry>> data;
List<List<ReadOnlyEntry>> // Where each ReadOnlyEntry is a wrapper for the Entry in the same list and at the same index as its Entry object.
List<IReadOnlyCollection<ReadOnlyEntry>> // Where each IReadOnlyCollection is a wrapper for the List<ReadOnlyEntry> at the same index in data.
IReadOnlyCollection<IReadOnlyCollection<ReadOnlyList>> readOnlyList // Which is a wrapper for the first item I listed.
The last item in the list would be exposed as public. The first lets me change entries, the second lets me add or delete entries, and the third lets me add or delete categories. I would have to keep these wrappers accurate whenever the data changes. This seems convoluted to me, so I'm wondering if there's a blatantly better way to handle this.
Edit 1:
To clarify, I know how to use List.asReadOnly(), and the stuff I proposed doing above will solve my problem. I'm just interested in hearing a better solution. Let me give you some code.
class Database
{
// Everything I described above takes place here.
// The data will be readable by this property:
public IReadOnlyCollection<IReadOnlyCollection<ReadOnlyList>> Data
{
get
{
return readOnlyList;
}
}
// These methods will be used to modify the data.
public void AddEntry(stuff);
public void DeleteEntry(index);
public void MoveEntry(to another category);
public void AddCategory(stuff);
public void DeleteCategory(index);
}
You can use List<T>.AsReadOnly() to return ReadOnlyCollection<T>.
Also, you're torturing the List<T> class storing the data the way you are. Build your own hierarchy of classes which store your individual lists.
.NET collections should support covariance, but they don't support it themselves (instead some interfaces support covariance https://msdn.microsoft.com/ru-ru/library/dd233059.aspx). Covariance means List<Conctrete> behaves like subclass of List<Base> if Concrete is subclass of Base. You can use interfaces covariation or just use casting like this:
using System.Collections.Generic;
namespace MyApp
{
interface IEntry
{
}
class Entry : IEntry
{
}
class Program
{
private List<List<Entry>> _matrix = null;
public List<List<IEntry>> MatrixWithROElements
{
get
{
return _matrix.ConvertAll(row => row.ConvertAll(item => item as IEntry));
}
}
public IReadOnlyList<List<IEntry>> MatrixWithRONumberOfRows
{
get
{
return _matrix.ConvertAll(row => row.ConvertAll(item => item as IEntry));
}
}
public List<IReadOnlyList<IEntry>> MatrixWithRONumberOfColumns
{
get
{
return _matrix.ConvertAll(row => row.ConvertAll(item => item as IEntry) as IReadOnlyList<IEntry>);
}
}
public IReadOnlyList<IReadOnlyList<IEntry>> MatrixWithRONumberOfRowsAndColumns
{
get
{
return _matrix.ConvertAll(row => row.ConvertAll(item => item as IEntry));
}
}
public void Main(string[] args)
{
}
}
}
Thanks to Matthew Watson for pointing on errors in my previous answer version.
You could make an interface for Entry which contains only getters; you would expose elements via this interface to provide read-only access:
public interface IEntry
{
int Value { get; }
}
The writable implementation would be simply:
public sealed class Entry : IEntry
{
public int Value { get; set; }
}
Now you can take advantage of the fact that you can return a List<List<Entry>> as a IReadOnlyCollection<IReadOnlyCollection<IEntry>> without having to do any extra work:
public sealed class Database
{
private readonly List<List<Entry>> _list = new List<List<Entry>>();
public Database()
{
// Create your list of lists.
List<Entry> innerList = new List<Entry>
{
new Entry {Value = 1},
new Entry {Value = 2}
};
_list.Add(innerList);
}
public IReadOnlyCollection<IReadOnlyCollection<IEntry>> Data => _list;
}
Note how simple the implementation of the Data property is.
If you need to add new properties to IEntry you would also have to add them to Entry, but you wouldn't need to change the Database class.
If you're using C#5 or earlier, Data would look like this:
public IReadOnlyCollection<IReadOnlyCollection<IEntry>> Data
{
get { return _list; }
}

Taking an object and adding it to the appropritae collection

I am doing a few labs and it has me creating multiple classes that are inheriting from a base class. i have created the base class, a student class that inherits from the base class, which creates a student and a teacher class that inherits from the base class, which creates a teacher. Now i am working on creating a school class that does not inherit any class. i have done most of what it is wanting me to do, but i am stuck on creating the appropriate methods to add the objects to its appropriate classes. I need assistance and guidance on how to create these methods so i may proceed. I am just going to post the Student class that i am working in right now and the instructions. I am not looking for someone to do my homework for me, i just cant seem to find anything online that can guide me in the right directions. thank you for your help.
Methods
Add(base) - Takes a teacher/student object and adds it to the
appropriate collection.
Print(base[]) - Private method that takes an
array of your base class object and prints all the elements of the
array.
3 Print(bool students = true) - Public method that prints out the
list of students, or list of teachers based upon the parameter value.
This is done by calling the Print(base[]) with the student[] or
teacher[] based upon the bool.
namespace BaseClass
{
class School
{
List<Teacher> staff = new List<Teacher>();
List<Student> students = new List<Student>();
public Student Students
{
get
{
students.Count();
return Students;
}
}
public Teacher Staff
{
get
{
if(Staff.EnumProp == Status.Employeed)
{
staff.Count();
}
return Staff;
}
}
public void Add(Teacher t1, Student s1) //not sure if this is correct or
//what to do in this method??
{
staff.Add(t1);
students.Add(s1);
//i also need help in the following methods. i am not sure what needs to be put
//in the parameter of the method, based on the instructions.
Based on requirement 1, you'd have to Add(Base c) and determine the collection to add to from there. e.g. (c is Teacher ? staff : students).Add(c). Normally such a class would have overloads (Add(Teacher) and Add(Student)) separately as well to be able to add directly.
public void Add(Base c)
{
if(c is Teacher)
staff.Add((Teacher)c);
else
students.Add((Student)c);
}
2 depends on the output type. With assignments outputting to the console is often enough, so you can use something like
void Print(params Base[] peeps)
{
foreach(var c in peeps)
c.Print();
}
No matter how Print is implemented, step 3 is actually very easy. You can just call your Print(Base[]) as stated in the requirements. To get that array, you have to determine which collection to use, just as in req. 1. (it does sound like 2 separate collections are wanted, otherwise a single collection could be used where Base exposes the role of the person).
public void Print(bool students = true)
{
if(students)
Print(this.students.ToArray());
else
Print(staff.ToArray());
}
PS, as mentioned in the comments the Students and Staff properties seem to expose some behavior that could be changed, but since that outside the scope of the question, won't go there unless you want us to ;)
Add(base) - Takes a teacher/student object and adds it to the appropriate collection.
For adding you can have two methods with same name but different signature. they are called method overloads. Compiler can distinguish between them by looking at the parameters they take.
These methods are both defined in base method. but better design would be to put each method in its appropriate class. (i.e Teacher and Student class)
public void Add(Teacher teacher)
{
staff.Add(teacher);
}
public void Add(Student student)
{
students.Add(student);
}
Print(base[]) - Private method that takes an array of your base class object and prints all the elements of the array.
If i understood correctly you want to print all elements of student or teacher. thats all?
In your base class you can have private method that prints array.
private void Print(Base[] array)
{
for (int i = 0; i < array.Length; i++)
{
Console.WriteLine(array[i].ToString());
}
}
It is better to override ToString method for both Student and Teacher class. for example this method is required in both classes.
public override string ToString() // write this method in both student and teacher classes.
{
return string.Format("Name : {0} , Age : {1}",studentName,studentAge ); // return optional information of student instance.
}
3 Print(bool students = true) - Public method that prints out the list of students, or list of teachers based upon the parameter value. This is done by calling the Print(base[]) with the student[] or teacher[] based upon the bool.
You just need a simple check.
public void Print(bool students = true)
{
if(students)
Print(Students.ToArray());
else
Print(Staff.ToArray());
}
This only works if its inside Base class behind Print(base[]). Otherwise Print(base[]) have to be protected.
A better design would be to add each print method in child classes separately.
In your get and set method what you are doing is really useless.
Count() is a linq method that counts and gives you the length of list. you can use the property of list itself. Count(without parenthesis) which directly gives you the length of list.
Also you dont store the result anywhere so thats why i said its useless. You may want to store the total count. then you can do this.
public int TotalCount
{
get { return staff.Count + students.Count; }
}

Accessing fields in a derived class

I'm creating a list of nodes on the fly through a user interface. In my List I can add any number of objects (AAA, BBB, etc) to the List based on the class structure below by instantiating these objects through reflection.
public abstract class Node : IDisposable
{
protected int x;
}
public class AAA : Node
{
public int iA;
}
public class BBB : Node
{
public int iB;
}
After creating the List I want to access the the extended fields in the derived objects. I know that I have to downcast to access the extended fields but in order to do that presently I have to perform an explicit cast.
foreach (Node nn in MyList) //assume the first node in the list is AAA
{
int m = ((namespace.AAA) nn).iA; //this works
int n = (AAA) nn).iA; //this works
}
I was wondering if I can use a string to create the actual downcast. Maybe it can't be done. Maybe I'm missing something. What I would like to do which DOESN'T work would be something like the following.
foreach (Node nn in MyList) //assume the first node in the list is AAA
{
Type t2 = nn.GetType(); //{Name = AAA; FullName = namespace.AAA} (*debugger*)
string str = t2.FullName; //namespace.AAA
int m = ((str) nn).iA; //this DOESN'T work
}
When I look at the value of nn in the debugger the FullName represents the Class I want to use for the downcast.
I could get around this by using a switch statement based on the string representing the class and hard code in the cast statement but because I have over 100 different nodes and I will be adding more nodes in the future, I would have to modify the switch statement every time a node is added. This is something I would prefer not to do if all possible.
Thanks in advance for any response.
Thanks to Douglas for pointing out that I could use FieldInfo to get the value of iA for example. I just wanted to expand a little more on this topic. If I wanted to take Class AAA and extend it through composition would I also be able to access the fields in those classes through the FieldInfo.
public class AAA : Node
{
public int iA;
public X[] XArray; //where X is some other random class with pubic fields
public Y[] YArray; //where Y is some other abstract class
}
What you are doing seems like a product of a faulty idea somewhere in your design.
Instead of having iA and iB in your classes, why doesn't the base node have a property called iNodeImplementation which you set in the constructor of AAA or BBB? Then you don't have to do all this fancy casting.
I have a feeling your trying to be too cute and missed some basic OOD principles. Consider how you can refactor your classes to make your code simpler.
Without going into the merits of whether this should be done, here's some sample code showing how it can be done using reflection:
Type aaaType = Type.GetType("namespace.AAA");
FieldInfo iAField = aaaType.GetField("iA", BindingFlags.Public |
BindingFlags.Instance);
int m = (int)iAField.GetValue(nn);
Why you don't try to set abstract properties in Node class and than implement in AAA and BBB.
public abstract class Node : IDisposable
{
protected int x;
public abstract int i;
}
public class AAA : Node
{
public override int i;
}
public class BBB : Node
{
public override int i;
}
And than use the foreach like this:
foreach (Node nn in MyList)
{
int m = nn.i;
}
To me, this is a problem in your object design, not in C#.
You've got a lot of nodes that you want to treat generically (great) but you want to be able to get specialized data from them in unique ways. This is not so great in the context of having a (possibly) unbounded amount of unique data.
The problem is that you want the best of both worlds: unique encapsulated data and free generic access to that data.
I would say that you need to take your Node design and think long and hard what kind of operations/accessing should be available to generic consumers of the nodes and provide that in an abstract base class or a small(ish) number of interfaces that provide that access.
Otherwise, you're looking at a lot of down-casting somewhere in your code or work with reflection to best guess things or a standard interface for describing and getting the values you want.

How do I add multiple objects to a single array?

I am designing a very simple inventory system for a game. I have run into an obstacle where I have the inventory (an array of a specific type) that would need to accept multiple types of objects. My code:
IWeapon[] inventory = new IWeapon[5];
public void initialiseInventory(IWeapon weapon, IArmour armour)
{
inventory[0] = weapon; // Index 0 always contains the equipped weapon
inventory[1] = armour; // Index 1 always contains the equipped armour
}
I would get an error stating that the array can't convert the armour object to a weapon object (which is the array type). I then thought I might make a superclass (well, interface to be precise) that IWeapon and IArmour would inherit from. But then I run into another error...
IItem[] inventory = new IItem[5];
public void initialiseInventory(IWeapon weapon, IArmour armour)
{
inventory[0] = weapon; // Index 0 always contains the equipped weapon
inventory[1] = armour; // Index 1 always contains the equipped armour
Console.WriteLine("The weapon name is: " + inventory[0].Name) // Problem!
}
Since the array type is IItem, it would only contain properties and methods from IItem, and not from IWeapon or IArmour. Thus the problem came in that I could not access the name of the weapon located in the subclass (subinterface) IWeapon. Is there a way I could redirect it somehow to look for properties in a subinterface (IWeapon or IArmour) rather than the superinterface (IItem)? Am I even on the right path?
Since the first item will always be a weapon, and the second will always be armor, you shouldn't use an array (or any data structure) at all. Just have two separate fields, one that holds a weapon and another an armor instance.
private IWeapon weapon;
private IArmour armor;
public void initialiseInventory(IWeapon weapon, IArmour armour)
{
this.weapon = weapon;
this.armor = armor;
}
This is an interesting (and common) puzzle. You have figured out its first part correctly: in order to store the elements in a single array, the array type must match the common ancestor of all elements that go into the array. Of course, this limits the functionality to only what's offered by that common ancestor, which apparently is not enough in your circumstances.
The second part (namely, what to do with elements once you have them all in the array) is a bit harder. You need either a type cast, or a multiple dispatch. The type cast is easy: just add (IWeapon) in front of the element:
((IWeapon)inventory[0]).Name
For multiple items, you can use LINQ:
foreach (IWeapon w in inventory.OfType<IWeapon>()) {
Console.WriteLine("The weapon name is: " + w.Name);
}
Multiple dispatch is a lot more complex. It lets you make methods virtual with respect to more than one object. In return you must sacrifice the simplicity offered by the language: calling methods would require making special objects, rather than calling methods directly. Take a look at the Visitor Pattern for some ideas of how to deal with multiple dispatch.
You can use the is operator to determine if a variable implements a specific interface and then cast that variable to an instance of that interface.
if (inventory[0] is IWeapon)
{
IWeapon myWeapon = (IWeapon)inventory[0];
Console.WriteLine("The weapon name is: " + myWeapon.Name);
}
In the parent class/ interface, you need to decide what common operations/ attributes are truly meant to go here.
It might be worth having the interface something like this:
Interface IItem
{
string name {get};
string itemType {get};
}
then you can just go
foreach(Iitem anItem in itemArray)
{
Console.WriteLine("The " + anItem.itemType + " is: " + anItem.Name);
}
It's not perfect, and raises questions about your model, but it is just something to think about.
Although I totally agree with the answer Servy gave:
If you really really want to use an array (or a List<IITem> ?) you only need to add the Name property to the IItem interface.
interface IItem
{
string Name {get;set;}
}
I doubt if it will help you on the long run, so I'd go for Servy's answer.
I detect a little confusion between interfaces and classes, but nevertheless, you should very simply make sure that IItem has the Name property on it (which, if its an interface, IWeapon and IArmour would need to implement), rather than putting the Name property on each subclass (no such thing as a "subinterface" :) )
Perhaps you should post the code of your interfaces/classes though....
Both weapons and armour have names, so that's a property that should go in the IItem interface.
Also, what Servy says makes sense, having an array for different kind of items doesn't make much sense as the specific positions always have the same type of item.
If you want to access them as an array, you can create a class that both has an array, and lets you access the equipped items with the specific type:
public class Inventory {
public IWeapon CurrentWeapon { get; }
public IArmour CurrentArmour { get; }
private IItem[] _items = new IItem[8];
public IItem[int idx] {
get {
return
idx == 0 ? CurrentWeapon :
idx == 1 ? CurrentArmour :
idx_items[idx - 2];
}
}
}
I have to add my 2 cents, because i found the question quite well asked and it may be a common problem.
I would go with something like this:
interface IItem
{
//some common properties / methods
}
interface IWEapon : IItem
{
string Name { get; set; } //maybe this should go to IItem? depends on your actual objects, of course
//some other wepaon specific properties / methods
}
interface IArmor : IItem
{
//some properties / methods
}
class Inventory
{
public Inventory(IWEapon startWeapon, IArmor startArmor)
{
CurrentWeapon = startWeapon;
CurrentArmor = startArmor;
//optional:
m_items.Add(startWeapon);
m_items.Add(startArmor);
}
private List<IItem> m_items = new List<IItem>();
IEnumerable<IItem> InventoryItems
{
get { return m_items; }
}
void AddItem(IItem item)
{
m_items.Add(item);
}
IWEapon CurrentWeapon
{
get;
set;
}
IArmor CurrentArmor
{
get;
set;
}
}
Why design a class for the inventory? Because you could add things like a TotalWeight or ItemCount property, etc. way more easily than if you have just an array of IItem.
Assuming you really require an array to store the different inventory items (and not just two separate fields) then it seems you could just use inheritance. I took the liberty of adding different properties to Weapon and Armor to clarify the use cases.
Base Class:
abstract class Item
{
public string Name { get; set; }
}
Derived Types:
class Weapon : Item
{
public int Power { get; set; }
}
class Armor : Item
{
public int Resistance { get; set; }
}
Example usage:
Item[] inventory = new Item[2];
inventory[0] = new Weapon { Name = "Singing Sword", Power = 10 };
inventory[1] = new Armor { Name = "Chainmail Shirt", Resistance = 5 };
// Note below that the Name property is always accessible because it is defined in the base class.
// Traverse only Weapon items
foreach (Weapon weapon in inventory.OfType<Weapon>())
{
Console.WriteLine(weapon.Power);
}
// Traverse only Armor items
foreach (Armor armor in inventory.OfType<Armor>())
{
Console.WriteLine(armor.Resistance);
}
// Travers all items
foreach (Item item in inventory)
{
Console.WriteLine(item.Name);
}

Categories