Am I done with this Linked List code? - c#

Hi I'm trying to get some practice with Linked Lists.
I Defined an Object class called Student:
public class Student
{
protected string Student_Name;
protected int Student_ID;
protected int Student_Mark;
protected char Student_Grade;
public Student() // default Constructor
{
Student_Name = " ";
Student_ID = 0;
Student_Mark = 0;
Student_Grade = ' ';
}
public Student(string Sname, int Sid, int Smark, char Sgrade) // Constructor
{
int len = sname.Length;
Student_Name = sname.Substring(0, len);
//Student_Name = sname.Substring(0, sname.Length);
Student_ID = Sid;
Student_Mark = Smark;
Student_Grade = Sgrade;
}
}
and then a Node class:
public class S_Node
{
public Student Element;
public S_Node Link;
public S_Node()
{
Element = new Student();
Link = null;
}
public Node(Student theElement)
{
Element = theElement;
Link = null;
}
}
and the LinkedList:
public class S_LinkedList
{
protected S_Node header;
protected S_Node tail;
public S_LinkedList()
{
header = new S_Node();
Tail = new S_Node();
header.Link = Tail;
}
// METHODS which i don't know how to do it (never use linkedlist before)
}
I need to organize this data using a “linkedlist data structure type”.
Contain all methods of linkedlist as Adding nodes to the list as I've learned -->(Insert),Deleting nodes from the list,as I've learned -->((Remove),Traversing the lists I've learned -->((PrintList),Finding a node in the list as I've learned -->((Find , FindPrevious) the problem I'm selflearning and I've tried to search the net and read more from the stupid C# that was a disaster.
I've done too much that I'm so sad that i don't know how to complete it .
I'm trying hard to Use this classes to write an executable program and to Test it .
If you don't want to help in completing this program (hope not) at least show me some real examples or ideas , after all I'm a selflearner geek :-)

the head of the list.
( item1
Element: student1
Next ------------> ( item2
) Element: student2
Next ------------> ( item3
) Element: student3
Next: null
)
the tail of the list.
First of all, for you to be able to write the StudentList class, you need to write the client code first. Client code is the code that uses your student list. Also, don't just write one thing at a time and throw it away. Instead write a whole bunch of [test] cases that exercise the different ways you need to interact with the StudentList. Write exceptional cases too. But don't be tempted to write a swiss-army knife of a class that does everything just because it can. Write the minimal amount of code that gets the job done.
How you need to use the class will heavily dictate how the class is constructed. This is the essence of TDD or Test Driven Design.
Your biggest problem that I can see is you have no idea how you want to use the class. So lets do that first.
// create a list of students and print them back out.
StudentList list = new StudentList();
list.Add( new Student("Bob", 1234, 2, 'A') );
list.Add( new Student("Mary", 2345, 4, 'C') );
foreach( Student student in list)
{
Console.WriteLine(student.Name);
}
I add the students to the list, and then I print them out.
I have no need for my client code to see inside the StudentList. Therefore StudentList hides how it implements the linked list. Let's write the basics of the StudentList.
public class StudentList
{
private ListNode _firstElement; // always need to keep track of the head.
private class ListNode
{
public Student Element { get; set; }
public ListNode Next { get; set; }
}
public void Add(Student student) { /* TODO */ }
}
StudentList is pretty basic. Internally it keeps track of the first or head nodes. Keeping track of the first node is obviously always required.
You also might wonder why ListNode is declared inside of StudentList. What happens is the ListNode class is only accessible to the StudentList class. This is done because StudentList doesn't want to give out the details to it's internal implementation because it is controlling all access to the list. StudentList never reveals how the list is implemented. Implementation hiding is an important OO concept.
If we did allow client code to directly manipulate the list, there'd be no point having StudentList is the first place.
Let's go ahead and implement the Add() operation.
public void Add(Student student)
{
if (student == null)
throw new ArgumentNullException("student");
// create the new element
ListNode insert = new ListNode() { Element = student };
if( _firstElement == null )
{
_firstElement = insert;
return;
}
ListNode current = _firstElement;
while (current.Next != null)
{
current = current.Next;
}
current.Next = insert;
}
The Add operation has to find the last item in the list and then puts the new ListNode at the end. Not terribly efficient though. It's currently O(N) and Adding will get slower as the list gets longer.
Lets optimize this a little for inserts and rewrite the Add method. To make Add faster all we need to do is have StudentList keep track of the last element in the list.
private ListNode _lastElement; // keep track of the last element: Adding is O(1) instead of O(n)
public void Add(Student student)
{
if( student == null )
throw new ArgumentNullException("student");
// create the new element
ListNode insert = new ListNode() { Element = student };
if (_firstElement == null)
{
_firstElement = insert;
_lastElement = insert;
return;
}
// fix up Next reference
ListNode last = _lastElement;
last.Next = insert;
_lastElement = insert;
}
Now, when we add, we don't iterate. We just need to keep track of the head and tail references.
Next up: the foreach loop. StudentList is a collection, and being a collection we want to enumerate over it and use C#'s foreach. The C# compiler can't iterate magically. In order to use the foreach loop We need to provide the compiler with an enumerator to use even if the code we write doesn't explicitly appear to use the enumerator.
First though, lets re-visit how we iterate over a linked list.
// don't add this to StudentList
void IterateOverList( ListNode current )
{
while (current != null)
{
current = current.Next;
}
}
Okay. so let's hook into C#'s foreach loop and return an enumerator. To do that we alter StudentList to implement IEnumerable. This is getting a little bit advanced, but you should be able to figure out what's going on.
// StudentList now implements IEnumerable<Student>
public class StudentList : IEnumerable<Student>
{
// previous code omitted
#region IEnumerable<Student> Members
public IEnumerator<Student> GetEnumerator()
{
ListNode current = _firstElement;
while (current != null)
{
yield return current.Element;
current = current.Next;
}
}
#endregion
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
You should be able to spot the linked list iteration in there. Don't get thrown by the yield keyword. All yield is doing is returning the current student back to the foreach loop. The enumarator stops returning students when it gets to the end of the linked list.
And that's it! The code works the way we want it to.
* This is by no means the only way to implement the list. I've opted to put the list logic in the StudentList and keep ListNode very basic. But the code does only what my very first unit test needs and nothing more. There are more optimizations you could make, and there are other ways of constructing the list.
Going forward: What you need to do is first create [unit] tests for what your code needs to do, then add the implementation you require.
* fyi I also rewrote the Student class. Bad naming and strange casing from a C# persepctive, not to mention the code you provided doesn't compile. I prefer the _ as a leader to private member variables. Some people don't like that, however you're new to this so I'll leave them in because they're easy to spot.
public class Student
{
private string _name;
private int _id;
private int _mark;
private char _letterGrade;
private Student() // hide default Constructor
{ }
public Student(string name, int id, int mark, char letterGrade) // Constructor
{
if( string.IsNullOrEmpty(name) )
throw new ArgumentNullException("name");
if( id <= 0 )
throw new ArgumentOutOfRangeException("id");
_name = name;
_id = id;
_mark = mark;
_letterGrade = letterGrade;
}
// read-only properties - compressed to 1 line for SO answer.
public string Name { get { return _name; } }
public int Id { get { return _id; } }
public int Mark { get { return _mark; } }
public char LetterGrade { get { return _letterGrade; } }
}
check parameters
pay attention to the different casing of properties, classes, and variables.
hide the default constructor. Why do I want to create students without real data?
provide some read-only properties.
This class is immutable as written (i.e. once you create a student, you can't change it).

I'll do one for you! You need to draw diagrams with each node as a box, and work out what code you need to use to change the list for each operation. See this for some inspiration:
http://en.wikipedia.org/wiki/Linked_list
The diagrams there don't show the main list class as a box, which you should have, with two arrows coming out of it for the header and tail.
Draw yourself some diagrams for the two cases in the Insert method to work out what's going on. One diagram for when there's nothing in the list and header is null, and another diagram for when there's something already in the list. Then from there work out the other operations.
public class S_LinkedList {
protected S_Node header = null;
protected S_Node tail = null;
public S_LinkedList()
{
}
// METHODS which i don't know how to do it (never use linkedlist before)
void Insert(Student s)
{
if( header == null )
{
header = new S_Node(s);
tail = header;
}
else
{
tail.Link = new S_Node(s);
tail = tail.Link;
}
}
}

The operations you are missing are:
Add:
set the link of the tail node to be the added node and set the tail to be the new node.
Remove/Delete:
is a bit tricky if you don't have a doubly linked list but with a singly linked list go throught he list from the head till you find the node you require keeping the previous node in a separate variable. When you find the node you are removing set the Link of the previous node to that nodes link. An optimization might be to check that it's not the link you are looking for.
Alternatively make it a doubly linked list and you don't need to keep track of the previous node.
Find:
Traverse the list from node to node till you find the one you are looking for.
read this wikipedia article for more info.

Look at this...
Although if you really want to learn how to do this you should write it in c or c++ at least then you'd be doing something useful...

Actually I don't see a reason to write your own linked list in C# (other then learning how it works) since the .NET already contains LinkedList generic class.

The concept of linked lists is not very difficult to understand. Implementation on the other hand ... can get a bit tricky.
I can also understand your frustration of trying to find information on the web about it. I have been in your boat before and everything varies from site to site. You really might want to invest in a data structures book as you I think the information you find will be much more clear and helpful than most information you find in the wild.
Implementing a linked list in Java/C# will be much easier if you have never used ll's before. However, once you get a better feel for it you will get a much better understanding for the ll's by creating them in C/C++.
From your code above, you will be better off thinking of each S_Node as just regular node that contains a Student object instead of thinking of it as a Student node (hope that makes sense). Same rules apply for your S_LinkedList class. A linked list is a list mode up of nodes. These nodes contain Student objects.
Hope this helps.

Try this as your Student class.
public class Student
{
protected string Name;
protected int ID;
protected int Mark;
protected char Grade;
public Student() // default Constructor
{
Name = "";
ID = 0;
Mark = 0;
Grade = '';
}
public Student(string Name, int ID, int Mark, char Grade) // Constructor
{
this.Name = Name;
this.ID = ID;
this.Mark = Mark;
this.Grade = Grade;
}
}

Your question, as I read it, is too vague. I would start by googling 'linked lists' or picking up a book on 'data structures'. When you run into a specific problem, ask it on here, and I'm sure someone will help you.

Related

How should I remove elements from a generic list based on the list s object's inclusion of elementfrom another list in C# using predicate logic?

I am trying to learn C# by making a simple program that shows the user sushi rolls given their desired ingredients. i.e. a user wants a roll with crab, and the program will spit out a list of sushi rolls that contain crab.
I've created a Roll class
public class Roll
{
private string name;
private List<string> ingredients = new List<string>();
}
With some getters and setters and other various methods.
In the GUI, I have some checkboxes which each call an update() method from the Control class, which will then need to check a list of rolls against a list of ingredients given by the GUI checkboxes. What I have is this
class Controller
{
static List<Roll> Rolls = new List<Roll>();
static RollList RL = new RollList();
static List<String> ingredients = new List<String>();
static Roll roll = new Roll();
}
public void update
{
foreach(Roll roll in Rolls)
{
foreach (String ingredient in ingredients)
if (!roll.checkForIngredient(ingredient))
Rolls.Remove(roll);
}
}
But a System.InvalidOperationException is thrown saying that because the collection was modified, the operation can't execute. OK, that's fair, but then what's the best way to do this? Here on Stack Overflow there's a post about removing elements from a generic list while iterating over it.
This was good and pointed me in the right direction, but unfortunately, my predicate condition simply doesn't match the top answer's.
It would have to iterate over the ingredients list, and I'm not even sure that's possible...
list.RemoveAll(roll => !roll.containsIngredient(each string ingredient in ingredients) );
shudder
I've tried the for loop, but I can't seem to get the enumeration to work either, and I wonder if it's even necessary to enumerate the class for just this method.
So I come here to try and find an elegant, professional solution to my problem. Keep in mind that I'm new to C# and I'm not all too familiar with predicate logic or enumeration on classes.
To use RemoveAll you can rewrite your condition to this:
list.RemoveAll(roll => !ingredients.All(roll.checkForIngredient));
This exploits the fact that when the compiler sees this, it will effectively rewrite it to this:
list.RemoveAll(roll => !ingredients.All(i => roll.checkForIngredient(i)));
Which is what you want. If not all the ingredients are present, remove the roll.
Now, having said that, since you say you're a beginner, perhaps you feel more comfortable keeping your loop, if you could just make it work (ie. stop crashing due to modifying the loop). To do that, just make a copy of the collection and then loop through the copy, you can do this by just modifying the foreach statement to this:
foreach(Roll roll in Rolls.ToList())
This will create a list based copy of the Rolls collection, and then loop on that. The list will not be modified, even if Rolls is, it is a separate copy containing all the elements of Rolls when it was created.
As requested in the comments, I'll try to explain how this line of code works:
list.RemoveAll(roll => !ingredients.All(roll.checkForIngredient));
The RemoveAll method, which you can see the documentation for here takes a predicate, a Predicate<T>, which is basically a delegate, a reference to a method.
This can be a lambda, syntax that creates an anonymous method, using the => operator. An anonymous method is basically a method declared where you want to use it, without a name, hence the anonymous part. Let's rewrite the code to use an anonymous method instead of a lambda:
list.RemoveAll(delegate(Roll roll)
{
return !ingredients.All(roll.checkForIngredient);
});
This is the exact same compiled code as for the lambda version above, just using the bit more verbose syntax of an anonymous method.
So, how does the code inside the method work.
The All method is an extension method, found on the Enumerable class: Enumerable.All.
It will basically loop through all the elements of the collection it is extending, in this case the ingredients collection of a single roll, and call the predicate function. If for any of the elements the predicate returns false, the result of calling All will also be false. If all the calls return true, the result will also be true. Note that if the collection (ingredients) is empty, the result will also be true.
So let's try to rewrite our lambda code, which again looked like this:
list.RemoveAll(roll => !ingredients.All(roll.checkForIngredient));
Into a more verbose method, not using the All extension method:
list.RemoveAll(delegate(Roll roll)
{
bool all = true;
foreach (var ingredient in ingredients)
if (!roll.checkForIngredient(ingredient))
{
all = false;
break;
}
return !all;
});
This now starts to look like your original piece of code, except that we're using the RemoveAll method, which needs a predicate that returns whether to remove the item or not. Since if all is false, we need to remove the roll, we use the not operator ! to reverse that value.
Since you are both new to C# but also asked for an elegant solution, I will give you an example of how to solve this using a more object-oriented approach.
First of all, any "thing" of significance should be modeled as a class, even if it has just one property. This makes it easier to extend the behavior later on. You already defined a class for Roll. I would also add a class for Ingredient:
public class Ingredient
{
private string _name;
public string Name
{
get { return _name; }
}
public Ingredient(string name)
{
_name = name;
}
}
Note the Name property which only has a getter, and the constructor which accepts a string name. This might look like unnecessary complexity at first but will make your code more straightforward to consume further down the road.
Next, we'll modify your Roll class according to this guideline and give it some helper methods that make it easier for us to check if a roll contains a certain (list of) ingredients:
public class Roll
{
private string _name;
private List<Ingredient> _ingredients = new List<Ingredient>();
public string Name
{
// By only exposing the property through a getter, you are preventing the name
// from being changed after the roll has been created
get { return _name; }
}
public List<Ingredient> Ingredients
{
// Similarly here, you are forcing the consumer to use the AddIngredient method
// where you can do any necessary checks before actually adding the ingredient
get { return _ingredients; }
}
public Roll(string name)
{
_name = name;
}
public bool AddIngredient(Ingredient ingredient)
{
// Returning a boolean value to indicate whether the ingredient was already present,
// gives the consumer of this class a way to present feedback to the end user
bool alreadyHasIngredient = _ingredients.Any(i => i.Name == ingredient.Name);
if (!alreadyHasIngredient)
{
_ingredients.Add(ingredient);
return true;
}
return false;
}
public bool ContainsIngredients(IEnumerable<Ingredient> ingredients)
{
// We use a method group to check for all of the supplied ingredients
// whether or not they exist
return ingredients.All(ContainsIngredient);
// Could be rewritten as: ingredients.All(i => ContainsIngredient(i));
}
public bool ContainsIngredient(Ingredient ingredient)
{
// We simply check if an ingredient is present by comparing their names
return _ingredients.Any(i => i.Name == ingredient.Name);
}
}
Pay attention to the ContainsIngredient and ContainsIngredients methods here. Now you can do stuff like if (roll.ContainsIngredient(ingredient)), which will make your code more expressive and more readable. You'll see this in action in the next class that I'm going to add, RollCollection.
You are modeling collections of food to pick from, presumably in the context of a restaurant menu or some similar domain. You might as well go ahead and model just that: a RollCollection. This will allow you to encapsulate some meaningful logic inside of the collection.
Again, this sort of thing tends to require some boilerplate code and may look overly complex at first, but it will make your classes easier to consume. So let's add a RollCollection:
public class RollCollection : IEnumerable<Roll>
{
private List<Roll> _rolls = new List<Roll>();
public RollCollection()
{
// We need to provide a default constructor if we want to be able
// to instantiate an empty RollCollection and then add rolls later on
}
public RollCollection(IEnumerable<Roll> rolls)
{
// By providing a constructor overload which accepts an IEnumerable<Roll>,
// we have the opportunity to create a new RollCollection based on a filtered existing collection of rolls
_rolls = rolls.ToList();
}
public RollCollection WhichContainIngredients(IEnumerable<Ingredient> ingredients)
{
IEnumerable<Roll> filteredRolls = _rolls
.Where(r => r.ContainsIngredients(ingredients));
return new RollCollection(filteredRolls);
}
public bool AddRoll(Roll roll)
{
// Similar to AddIngredient
bool alreadyContainsRoll = _rolls.Any(r => r.Name == roll.Name);
if (!alreadyContainsRoll)
{
_rolls.Add(roll);
return true;
}
return false;
}
#region IEnumerable implementation
public IEnumerator<Roll> GetEnumerator()
{
foreach (Roll roll in _rolls)
{
yield return roll;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
WhichContainIngredients is the thing we were really looking for, as it allows you to do something like this:
// I have omitted the (proper) instantiation of Rolls and ChosenIngredients for brevity here
public RollCollection Rolls { get; set; }
public List<Ingredient> ChosenIngredients { get; set; }
public void Update()
{
Rolls = Rolls.WhichContainIngredients(ChosenIngredients);
}
This is simple and clean, just the sort of thing you want to be doing in your presentation layer. The logic to accomplish your requirement is now nicely encapsulated in the RollCollection class.
EDIT: a more complete (but still simplified) example of how your Controller class might end up looking like:
public class Controller
{
private RollCollection _availableRolls = new RollCollection();
private List<Ingredient> _availableIngredients = new List<Ingredient>();
public RollCollection AvailableRolls
{
get { return _availableRolls; }
}
public List<Ingredient> AvailableIngredients
{
get { return _availableIngredients; }
}
public RollCollection RollsFilteredByIngredients
{
get { return AvailableRolls.WhichContainIngredients(ChosenIngredients); }
}
public List<Ingredient> ChosenIngredients { get; set; }
public Controller()
{
ChosenIngredients = new List<Ingredient>();
InitializeTestData();
}
private void InitializeTestData()
{
Ingredient ingredient1 = new Ingredient("Ingredient1");
Ingredient ingredient2 = new Ingredient("Ingredient2");
Ingredient ingredient3 = new Ingredient("Ingredient3");
_availableIngredients.Add(ingredient1);
_availableIngredients.Add(ingredient2);
_availableIngredients.Add(ingredient3);
Roll roll1 = new Roll("Roll1");
roll1.AddIngredient(ingredient1);
roll1.AddIngredient(ingredient2);
Roll roll2 = new Roll("Roll2");
roll2.AddIngredient(ingredient3);
_availableRolls.AddRoll(roll1);
_availableRolls.AddRoll(roll2);
}
}
I am trying to learn C# by making a simple program that shows the user
sushi rolls given their desired ingredients. i.e. a user wants a roll
with crab, and the program will spit out a list of sushi rolls that
contain crab.
Here's my solution to the given problem:
public class Roll
{
public string Name { get; set; }
private List<string> ingredients = new List<string>();
public IList<string> Ingredients { get { return ingredients; } }
public bool Contains(string ingredient)
{
return Ingredients.Any(i => i.Equals(ingredient));
}
}
You can use the LINQ extension method .Where to filter your collection of Rolls
public class Program
{
static void Main()
{
var allRolls = new List<Roll>
{
new Roll
{
Name = "Roll 1",
Ingredients = { "IngredientA", "Crab", "IngredientC" }
},
new Roll
{
Name = "Roll 2",
Ingredients = { "IngredientB", "IngredientC" }
},
new Roll
{
Name = "Roll 3",
Ingredients = { "Crab", "IngredientA" }
}
};
var rollsWithCrab = allRolls.Where(roll => roll.Contains("Crab"));
foreach (Roll roll in rollsWithCrab)
{
Console.WriteLine(roll.Name);
}
}
}
From what I see you're trying to remove all rolls that don't contain crab from your list of rolls. A better approach is to filter out those rolls that don't contain crab (using .Where), you can then use .ToList() if you need to manipulate the whole list directly rather than iterating through the collection (fetching one item at a time).
You should read up on Delegates, Iterators, Extension Methods and LINQ to better understand what's going on under the covers.

"Writable" reference to object

Not sure I'm able to formulate this question in a way someone would simply understand, so lets have a cool marketing example:
public class Part
{
public MemberType member;
...
}
public class Product
{
public Part part1;
...
}
...
Product product = new Product();
I need to modify the public product's part1. So, the natural method is to write something like:
product.part1 = new Part();
Now, an algorithm (let's say a sort of search one) would go through the product object and identify the part1 as an interesting part and returns reference to it:
Part Search(Product product)
{
Part part = null;
...
part = product.part1;
...
return part;
}
...
interesting_part = Search(product);
We can alter the product object via the interesting_part like
interesting_part.member = whatever;
Now, the question: in c/c++ if the Product.part1 is pointer to Part and Search returns address of this pointer, we could replace the part1 just by assigning new value to this address. AFAIK this is not possible for c# reference:
interesting_part = new Part();
Just creates new object and copies its reference to the interresting_part, but without knowing the member parent (product object), we are not able to modify the (product.part1) reference, just its content. We would need second level of the reference.
Is there something like "ref reference" type which would accept reference addresses? In such hypothetical case the search would return ref Part and assigning to such value would replace the referenced object with the new one.
Thanks.
You could create a Reference class
class Reference<T>
{
private Func<T> m_Getter;
private Action<T> m_Setter;
public Reference(Func<T> getter, Action<T> setter)
{
m_Getter = getter;
m_Setter = setter;
}
public T Value
{
get{return m_Getter();}
set{m_Setter(value);}
}
}
Now you can say
Reference<Part> Search(Product product)
{
Part part = null;
...
part = product.part1;
var reference=new Reference<Part>(()=>product.part, (value)=>product.part1=value);
return refernce;
}
var partReference = Search(product);
partReference.Value = someNewPart;
In a very similar situation, I keep a reference of the parent in each child object. Simple and works.
public class Part
{
public MemberType member;
...
public Product parent;
Part(Product p)
{
parent = p;
}
}
public class Product
{
public Part part1;
...
}
I don't think you can do that. You would need to mutate a reference to you product object, or have some other added layer of reference.
So you need to build a Proxy object. The Product would get a reference to the Proxy and the (hidden) Part can be exchanged. This is a common OO design pattern. Of course the Proxy can delegate method calls to the Part.
If you want to change the field, you can do this,
class Program
{
static void Main(string[] args)
{
var holder = new Holder();
holder.CurrentPart = new Part() { Name = "Inital Part" };
Console.WriteLine(holder.CurrentPart.Name);
TestRef(ref holder.CurrentPart);
Console.WriteLine(holder.CurrentPart.Name);
Console.ReadKey();
}
public static void TestRef(ref Part part)
{
part = new Part() { Name = "changed" };
}
}
public class Part
{
public string Name;
}
public class Holder
{
public Part CurrentPart;
}
This won't work with property, indexers and so.
As far as I know, there isn't any way to alter an object's "parent" without having a reference to it. So I believe the official answer to your question as written is "no".
That said, there are many ways to accomplish the task as written. The easiest option is to add a reference to the parent from the part object. You end up with something like:
public class Part
{
public Product parentProduct;
public MemberType member;
...
}
Now whenever you have a part object you also know what product the part goes with (IF it does indeed go with a part at all). This is not necessarily a bad coding style but there certainly are pitfalls. You can update the product, but forget to update the parts in that product, you are coding so that parts have one product, but what if that part has many products? You can see how this works, but it can get complicated.
Taking this and making it more generic you can have reference the parent as an object type. That looks like:
public class Part
{
public object parent;
public MemberType member;
...
}
Now when you want to use the parent you can write something like:
var parentProduct = myPart.parent as Product;
This will convert the parent to a product or will assign null if the parent is not of the type Product. Now parts can have parents of any given type you would want and you have made the pattern more flexible.
One final pattern I know people use frequently is delegates. This allows you to pass in a function effectively modifying the way "search" is working. Say what you really want to do is search, then process the results in some manner, but you want that processing to be flexible (this may be what you were doing with the results). In that case, you can use delegates as follows:
// define the delegate
public delegate void ProcessResultDelegate(Product result, Part interestingPart);
// an example search function
public static void RunSearch(IEnumerable<Product> products, ProcessResultDelegate processingHelper)
{
// run the search... then call the processing function
processingHelper(searchResult, interestingPart);
}
This pattern is more useful when you want to modify the behavior of a routine rather than the return value from that routine.
Anyways, hope these patterns help some!

Custom Collection returns first element empty

I'm trying to recreate the generic List collection. This is my code to Add items to the collection and Show all of them:
public class Collect<TItem>
{
public Collect<TItem> collectObject;
public TItem firstObject;
public void Add(TItem item)
{
if (collectObject == null)
{
collectObject = new Collect<TItem>();
collectObject.firstObject = item;
}
else
{
this.collectObject.Add(item);
}
}
public void Show()
{
if (firstObject != null)
Console.WriteLine(firstObject.ToString());
if (collectObject != null)
collectObject.Show();
}
You'd use this class like this:
Collect<int> test = new Collect<int>();
test.Add(2);
test.Add(10);
test.Add(30);
test.Add(3);
test.Show();
It prints all of the values above, but the first item is always 0.
0
2
10
30
3
This is because the very first firstObject variable is never assigned and gets the default value, but I can't figure out a way to get this fixed. The book I learned this assigns the first firstObject variable in a constructor that expects a TItem object, but I want to do it without using a constructor for this collection (to recreate a List)
I know this is exactly the same like how a generic List works, but I just want to understand the logic behind it. Thanks for the help.
You can make your TItem nullable, which allows your test to work. Also, you need to set the firstObject in the top instance of Collect, not the referenced one.
public class Collect<TItem> where TItem : struct
{
public Collect<TItem> collectObject;
public TItem? firstObject;
public void Add(TItem item)
{
if (collectObject == null)
{
collectObject = new Collect<TItem>();
firstObject = item;
}
else
{
this.collectObject.Add(item);
}
}
public void Show()
{
if (firstObject.HasValue)
Console.WriteLine(firstObject.ToString());
if (collectObject != null)
collectObject.Show();
}
}
OK, this is doing my head in, but I think you want to do something like:
if (collectObject == null)
{
collectObject = new Collect<TItem>();
this.firstObject = item;
}
because otherwise you are never actually assigning anythign tothe firstobject property of the object you are creating.
What you doing wrong is collectObject.firstObject = item; should be this.firstObject = item;
I think you just have to change the line:
collectObject.firstObject = item;
to
firstObject = item;
This way your custom collection will always be represented by a "head" and a "tail" - I assume this is what you are tryin' to acomplish.
In other words when adding an item, you say "If this is the first time to add, then this is my 'head' of the list, else - insert it into the 'tail' of the list". Printing is with the same idea - print the "head" and then call the tail's print method (in your code 'Show' method).
First, this is certainly not how System.Collections.Generic.List<T> works. It uses an array internally, not a singly-linked list as you do. LinkedList<T> is somewhat similar to your collection, except it uses a doubly liked list.
Now, onto your issue. The problem with your collection is that it is not able to represent an empty value and it seems you want that. What I would suggest is to create another public class that represents the whole collection and change your Collect<T> only to an internal implementation (let's call it Node<T>). This way, the new collection class can contain null reference to Node<T>, when it is first constructed, which signifies an empty collection.
If this were production code, I'm pretty sure you would actually need to do something like this, because you are going to want to keep some information on a per-collection basis (like count).
Another option (which is usually taken by lists in functional languages) is to create an inheritance hierarchy similar to the following:
abstract class Node<T>
{ }
class FullNode<T> : Node<T>
{
public T Item { get; private set; }
public Node<T> Next { get; private set }
// constructor and possibly other members
}
class EmptyNode<T> : Node<T>
{ }
This way, you have separate types to represent a full node and an empty node. In those lists, it is usual to add new items to the front, not to the back, though.
I would suggest at least one other improvement, regarding the speed of adding, but I suppose your book will get to that.
Also, I'm quite sure this is the case, but I really hope you're not planning on using this code in any kind of production environment and that it is just an learning exercise.
Just to add a little bit more information...
The reason the 0 is being written out is because you have a != null check on the firstObject. Obviously, the default value of an integer is not null, it is zero, so when firstObject hasn't been set it will be zero and not null. I guess if you want to exclude any value that is not the default for that type you could change your check to:
if (firstObject != default(TItem))
That's probably not exactly what you want though as I'm sure zero could be a valid value in this instance.
Try a nullable type
Collect<int?> test = new Collect<int?>();

Converting nested foreach loops to LINQ

I've written the following code to set the properties on various classes. It works, but one of my new year's rsolutions is to make as much use of LINQ as possible and obviously this code doesn't. Is there a way to rewrite it in a "pure LINQ" format, preferably without using the foreach loops? (Even better if it can be done in a single LINQ statement - substatements are fine.)
I tried playing around with join but that didn't get me anywhere, hence I'm asking for an answer to this question - preferably without an explanation, as I'd prefer to "decompile" the solution to figure out how it works. (As you can probably guess I'm currently a lot better at reading LINQ than writing it, but I intend to change that...)
public void PopulateBlueprints(IEnumerable<Blueprint> blueprints)
{
XElement items = GetItems();
// item id => name mappings
var itemsDictionary = (
from item in items
select new
{
Id = Convert.ToUInt32(item.Attribute("id").Value),
Name = item.Attribute("name").Value,
}).Distinct().ToDictionary(pair => pair.Id, pair => pair.Name);
foreach (var blueprint in blueprints)
{
foreach (var material in blueprint.Input.Keys)
{
if (itemsDictionary.ContainsKey(material.Id))
{
material.Name = itemsDictionary[material.Id];
}
else
{
Console.WriteLine("m: " + material.Id);
}
}
if (itemsDictionary.ContainsKey(blueprint.Output.Id))
{
blueprint.Output.Name = itemsDictionary[blueprint.Output.Id];
}
else
{
Console.WriteLine("b: " + blueprint.Output.Id);
}
}
}
Definition of the requisite classes follow; they are merely containers for data and I've stripped out all the bits irrelevant to my question:
public class Material
{
public uint Id { get; set; }
public string Name { get; set; }
}
public class Product
{
public uint Id { get; set; }
public string Name { get; set; }
}
public class Blueprint
{
public IDictionary<Material, uint> Input { get; set; }
public Product Output { get; set; }
}
I don't think this is actually a good candidate for conversion to LINQ - at least not in its current form.
Yes, you have a nested foreach loop - but you're doing something else in the top-level foreach loop, so it's not the easy-to-convert form which just contains nesting.
More importantly, the body of your code is all about side-effects, whether that's writing to the console or changing the values within the objects you've found. LINQ is great when you've got a complicated query and you want to loop over that to act on each item in turn, possibly with side-effects... but your queries aren't really complicated, so you wouldn't get much benefit.
One thing you could do is give Blueprint and Product a common interface containing Id and Name. Then you could write a single method to update the products and blueprints via itemsDictionary based on a query for each:
UpdateNames(itemsDictionary, blueprints);
UpdateNames(itemsDictionary, blueprints.SelectMany(x => x.Input.Keys));
...
private static void UpdateNames<TSource>(Dictionary<string, string> idMap,
IEnumerable<TSource> source) where TSource : INameAndId
{
foreach (TSource item in source)
{
string name;
if (idMap.TryGetValue(item.Id, out name))
{
item.Name = name;
}
}
}
This is assuming you don't actually need the console output. If you do, you could always pass in the appropriate prefix and add an "else" block in the method. Note that I've used TryGetValue instead of performing two lookups on the dictionary for each iteration.
I'll be honest, I did not read your code. For me, your question answered itself when you said "code to set the properties." You should not be using LINQ to alter the state of objects / having side effects. Yes, I know that you could write extension methods that would cause that to happen, but you'd be abusing the functional paradigm poised by LINQ, and possibly creating a maintenance burden, especially for other developers who probably won't be finding any books or articles supporting your endeaver.
As you're interested in doing as much as possible with Linq, you might like to try the VS plugin ReSharper. It will identify loops (or portions of loops) that can be converted to Linq operators. It does a bunch of other helpful stuff with Linq too.
For example, loops that sum values are converted to use Sum, and loops that apply an internal filter are changed to use Where. Even string concatenation or other recursion on an object is converted to Aggregate. I've learned more about Linq from trying the changes it suggests.
Plus ReSharper is awesome for about 1000 other reasons as well :)
As others have said, you probably don't want to do it without foreach loops. The loops signify side-effects, which is the whole point of the exercise. That said, you can still LINQ it up:
var materialNames =
from blueprint in blueprints
from material in blueprint.Input.Keys
where itemsDictionary.ContainsKey(material.Id)
select new { material, name = itemsDictionary[material.Id] };
foreach (var update in materialNames)
update.material.Name = update.name;
var outputNames =
from blueprint in blueprints
where itemsDictionary.ContainsKey(blueprint.Output.Id)
select new { blueprint, name = itemsDictionary[blueprint.Output.Id] };
foreach (var update in outputNames)
update.Output.Name = update.name;
What about this
(from blueprint in blueprints
from material in blueprint.Input.Keys
where itemsDictionary.ContainsKey(material.Id)
select new { material, name = itemsDictionary[material.Id] })
.ToList()
.ForEach(rs => rs.material.Name = rs.name);
(from blueprint in blueprints
where itemsDictionary.ContainsKey(blueprint.Output.Id)
select new { blueprint, name = itemsDictionary[blueprint.Output.Id] })
.ToList()
.ForEach(rs => rs.blueprint.Output.Name = rs.name);
See if this works
var res = from blueprint in blueprints
from material in blueprint.Input.Keys
join item in items on
material.Id equals Convert.ToUInt32(item.Attribute("id").Value)
select material.Set(x=> { Name = item.Attribute("id").Value; });
You wont find set method, for that there is an extension method created.
public static class LinqExtensions
{
/// <summary>
/// Used to modify properties of an object returned from a LINQ query
/// </summary>
public static TSource Set<TSource>(this TSource input,
Action<TSource> updater)
{
updater(input);
return input;
}
}

How to use Comparer for a HashSet

As a result of another question I asked here I want to use a HashSet for my objects
I will create objects containing a string and a reference to its owner.
public class Synonym
{
private string name;
private Stock owner;
public Stock(string NameSynonym, Stock stock)
{
name=NameSynonym;
owner=stock
}
// [+ 'get' for 'name' and 'owner']
}
I understand I need a comparer , but never used it before. Should I create a separate class? like:
public class SynonymComparer : IComparer<Synonym>
{
public int Compare(Synonym One, Synonym Two)
{ // Should I test if 'One == null' or 'Two == null' ????
return String.Compare(One.Name, Two.Name, true); // Caseinsesitive
}
}
I prefer to have a function (or nested class [maybe a singleton?] if required) being PART of class Synonym instead of another (independent) class. Is this possible?
About usage:
As i never used this kind of thing before I suppose I must write a Find(string NameSynonym) function inside class Synonym, but how should I do that?
public class SynonymManager
{
private HashSet<SynonymComparer<Synonym>> ListOfSynonyms;
public SynonymManager()
{
ListOfSymnonyms = new HashSet<SynonymComparer<Synonym>>();
}
public void SomeFunction()
{ // Just a function to add 2 sysnonyms to 1 stock
Stock stock = GetStock("General Motors");
Synonym otherName = new Synonym("GM", stock);
ListOfSynonyms.Add(otherName);
Synonym otherName = new Synonym("Gen. Motors", stock);
ListOfSynonyms.Add(otherName);
}
public Synonym Find(string NameSynomym)
{
return ListOfSynonyms.??????(NameSynonym);
}
}
In the code above I don't know how to implement the 'Find' method. How should i do that?
Any help will be appreciated
(PS If my ideas about how it should be implemented are completely wrong let me know and tell me how to implement)
A HashSet doesn't need a IComparer<T> - it needs an IEqualityComparer<T>, such as
public class SynonymComparer : IEqualityComparer<Synonym>
{
public bool Equals(Synonym one, Synonym two)
{
// Adjust according to requirements.
return StringComparer.InvariantCultureIgnoreCase
.Equals(one.Name, two.Name);
}
public int GetHashCode(Synonym item)
{
return StringComparer.InvariantCultureIgnoreCase
.GetHashCode(item.Name);
}
}
However, your current code only compiles because you're creating a set of comparers rather than a set of synonyms.
Furthermore, I don't think you really want a set at all. It seems to me that you want a dictionary or a lookup so that you can find the synonyms for a given name:
public class SynonymManager
{
private readonly IDictionary<string, Synonym> synonyms = new
Dictionary<string, Synonym>();
private void Add(Synonym synonym)
{
// This will overwrite any existing synonym with the same name.
synonyms[synonym.Name] = synonym;
}
public void SomeFunction()
{
// Just a function to add 2 synonyms to 1 stock.
Stock stock = GetStock("General Motors");
Synonym otherName = new Synonym("GM", stock);
Add(otherName);
ListOfSynonyms.Add(otherName);
otherName = new Synonym("Gen. Motors", stock);
Add(otherName);
}
public Synonym Find(string nameSynonym)
{
// This will throw an exception if you don't have
// a synonym of the right name. Do you want that?
return synonyms[nameSynonym];
}
}
Note that there are some questions in the code above, about how you want it to behave in various cases. You need to work out exactly what you want it to do.
EDIT: If you want to be able to store multiple stocks for a single synonym, you effectively want a Lookup<string, Stock> - but that's immutable. You're probably best storing a Dictionary<string, List<Stock>>; a list of stocks for each string.
In terms of not throwing an error from Find, you should look at Dictionary.TryGetValue which doesn't throw an exception if the key isn't found (and also returns whether or not the key was found); the mapped value is "returned" in an out parameter.
Wouldn't it be more reasonable to scrap the Synonym class entirely and have list of synonyms to be a Dictonary (or, if there is such a thing, HashDictionary) of strings?
(I'm not very familiar with C# types, but I hope this conveys general idea)
The answer I recommend (edited, now respects the case):
IDictionary<string, Stock>> ListOfSynonyms = new Dictionary<string,Stock>>();
IDictionary<string, string>> ListOfSynForms = new Dictionary<string,string>>();
class Stock
{
...
Stock addSynonym(String syn)
{
ListOfSynForms[syn.ToUpper()] = syn;
return ListOfSynonyms[syn.ToUpper()] = this;
}
Array findSynonyms()
{
return ListOfSynonyms.findKeysFromValue(this).map(x => ListOfSynForms[x]);
}
}
...
GetStock("General Motors").addSynonym('GM').addSynonym('Gen. Motors');
...
try
{
... ListOfSynonyms[synonym].name ...
}
catch (OutOfBounds e)
{
...
}
...
// output everything that is synonymous to GM. This is mix of C# and Python
... GetStock('General Motors').findSynonyms()
// test if there is a synonym
if (input in ListOfSynonyms)
{
...
}
You can always use LINQ to do the lookup:
public Synonym Find(string NameSynomym)
{
return ListOfSynonyms.SingleOrDefault(x => x.Name == NameSynomym);
}
But, have you considered using a Dictionary instead, I believe it is better suited for extracting single members, and you can still guarantee that there are no duplicates based on the key you choose.
I am not sure that lookup time is of SingleOrDefault, but I am pretty sure it is linear (O(n)), so if lookup time is important to you, a Dictionary will provide you with O(1) lookup time.

Categories

Resources