i wan to create a linked list that contains the name , age and address of some people , so far i created that code :
LinkedList<string> details = new LinkedList<string>();
details.AddFirst("Name1");
details.AddLast("Name2");
details.AddLast("Name3");
foreach (var display in details)
{
Console.WriteLine(display);
}
ok so now it works fine , but i just input the name , how can i input the age and address , is it like array ? i just don`t know much about linkedlists , and also i tried to delete some nodes of the linkedlist but i failed :
foreach (var item in details)
{
if (item.Contains("Name3"))
{
details.Remove(item);
}
}
but i get that error :
Unhandled Exception: System.InvalidOperationException: Collection was modified after the enumerator was instantiated.
and finally , how can i edit a linkedlist item , like renaming Name2 to Name13 or anything , i would really appreciate any help , just give me idea and i`ll continue digging . Thanks in advance .
You can't remove elements from the list while iterating a list using foreach loop.
if (details.Remove("Name3"))
Console.WriteLine("Removed");
else
Console.WriteLine("Not Found");
A linked list is like an array in that it is a collection of data. Each item in the list stores a link to the next item (and often the previous), hence the name.
You can't modify a list you're looping over, because your reference into the list will then be invalid.
If you wish to add extra information within the list, simply create a class which encapsulates that information, as the LinkedList is a generic type. For example:
//Structure to hold extra information
public class PersonDetails
{
public string Name {get; private set;}
public int Age {get; private set;}
public string Address {get; private set;}
//Constructor
public PersonDetails(string name, int age, string address)
{
this.Name = name;
this.Age = age;
this.Address = address;
}
}
Then you can create a new linked list containing those types:
LinkedList<PersonDetails> list = new LinkedList<PersonDetails>();
list.AddFirst(new PersonDetails("Name", 22, "Address"));
Note that you cannot modify a collection when you are enumerating it, you need to perform your check and modify it outside of your foreach loop.
If you can use LINQ, you can convert your code to a linq approach such as:
details = details.Where(item => !item.Contains("Name3")).ToList();
Related
I posted a question 9 days ago but I feel I have more information to add and it would get seen better as a new question. Also I am not allowed to use LINQ so I couldn't use the solution posted
I have a student management tool which allows me to do things such as add, edit and delete students. I have a listbox on the main form which holds studentInfo. I have added the data to the listbox by reading in a CSV containing a column for studentID and a column for studentMark.
I have a class called ModuleData which holds 3 public list structures:
one to hold all the StudentID
one to hold all the StudentMarks
one to hold all the studentInfo(so just the studentID and studentMark but both together.)
My ModuleData class:
namespace Assignment_2_module_marks
{
static class ModuleData
{
public static List<string> studentNumber = new List<string>();
public static List<string> studentMarks = new List<string>();
public static List<string> studentInfo = new List<string>();
}
}
My form_load to populate the listbox on the mainform with some studentinfo:
private void Form1_Load(object sender, EventArgs e)
{
string studentRec; // Declaring string variable
StreamReader inputFile = File.OpenText("COM122.csv");
while (!inputFile.EndOfStream) /
{
studentRec = inputFile.ReadLine();
ModuleData.studentInfo = studentRec.Split(',').ToList();
ModuleData.studentNumber.Add(ModuleData.studentInfo[0]); studentNumber
ModuleData.studentMarks.Add(ModuleData.studentInfo[1]);
lstMarks.Items.Add(ModuleData.studentNumber[0] + " : " + ModuleData.studentInfo[1]);
}
inputFile.Close(); // closes the file
}
I want to be able to click the 'delete' button on the mainform which then opens a new form called deleteRecord. On the delete record form I ask the user for a StudentID and StudentMark. I then want to take those two pieces of data and look through the StudentInfo list and check if any students have the ID and Mark that the user entered in the delete form. If there is a student with the ID and Mark that was entered then I want to delete them from the StudentInfo list and then update the listbox on the mainform so that the student isn't there anymore, if no student is found I want an error to display to tell the user the student doesnt exist
I am not sure how to go about this since I am new to C#
Any help would be appreciated
Here is some psuedo code, I won't write the whole thing for you since this is homework.
var deletedID = -1;
for(int i=0; i< ModuleData.studentInfo.Count; i++)
{
if (ModuleData.studentInfo[i] == studentIDToDelete + " : " + studentMarkToDelete)
{
deletedID = i;
break;
}
}
if (deletedID != -1)
//now remove from lists and reload listbox (hint remove at i)
A much better way to do this would be to have a students class and fill that object with the students and marks. Then you could bind the list of objects directly to the listbox, and use the same list to delete a student.
Knowing this is homework I will try and be more informative rather than providing the answer:
First thing you should do is think of the ModuleData class as a model:
public partial class ModuleData
{
public List<string> studentNumber {get; set;}
public List<string> studentMarks {get; set;}
public List<string> studentInfo {get; set;}
}
You can then populate this model by instantiating it and assigning data to it:
ModuleData entity = new ModuleDate();
entity.studentNumbder = list1;
entity.studentMarks = list2;
entity.studentInfo = list3;
This model will be the object you use to query any datasource and do any CRUD to it.
On Form_Load iterate through the file and get your variables from the comma delimited string. Use this data to populate your ModuleData object and add it to your listbox.
Once you have your ListBox data source populated you can then use user defined parameters to query your ListBox data source and delete it if need be.
heres some psudo code:
foreach(var listItem in lstMarks.Items){
if listItem is parameters then remove from lstMarks
}
I hope this steers you in the right direction.
I'm creating a product and checkout page. In the product page when a button is pressed I do this
Session["code"] = productLabel.Text;
Session["description"] = descriptionTextBox.Text;
Session["price"] = priceLabel.Text;
Response.Redirect("cart.aspx");
Then in the cart page I have
if ((Session["code"] != null))
{code = (Session["code"]).ToString();}
if ((Session["description"] != null))
{ description = (Session["description"]).ToString(); }
if ((Session["price"] != null))
{price = (Session["price"]).ToString(); }
string item = code + " " + description + " " + price;
cartList.Items.Add(item);
This works, however my problem is when I then add another product to the list, it overrides my first item so theirs only one item in there at a time. How can I keep track of whats currently/previously in there?
Thanks a lot!
You'll probably want to rethink the entire concept and store some custom class instead, one thing you can do is create a list of items in the cart and store that list in the Session.
[Serializable]
public class Item
{
public string Code {get;set;}
public string Description {get;set;}
public string Price {get;set;}
}
List<Item> cart=new List<Item>();
Item item=new Item();
item.Code=productLabel.Text;
item.Description=descriptionTextBox.Text;
item.Price=priceLabel.Text;
cart.Add(item);
Session["cart"]=cart;
//then later pull it out...
List<Item> cart=Session["cart"] as List<Item>; //youll want to check for null etc
//and add another item
Item newItem=new Item();
newItem.Code=productLabel.Text;
newItem.Description=descriptionTextBox.Text;
newItem.Price=priceLabel.Text;
cart.add(newItem);
There's a ton wrong with your architecture. For instance, an enterprising individual could use their browser's tools to change the value in priceLabel.Text and potentially pay less (or nothing!) for their order. But hopefully this gives you an idea about how to proceed.
public class Item
{
public string Code {get;set;}
public string Description {get;set;}
public string Price {get;set;}
}
you can create kind of like a in memory cache to store your items:
public static readonly ConcurrentDictionary<string,List<Item>> myMemoryCache = new ConcurrentDictionary<string,List<Item>>();
and use this as the data source.
You can use the same "key" for multiple entries or you an change this to whatever you like.
Be sure to initialize this in your App_Start
I need to create a list with more than 400 items and each item has 3 properties, in c#. Like:
Name
Profession
Age
Marital Status
The relevant detail is that, to access individual data, I do not want to loop over each Name with a foreach or something else, but I want to access the data directly.
Assuming I need data from a person called Ana_Salgado, which name is stored in a string called PersonName, would it be possible to access these data like: PersonName.Profession?
Any ideas? Thank you in advance :)
You can use Dictionary, in this way
Class Members
{
public string Profession {get; set;}
public string Age {get; set;}
public string MaritalStatus {get; set;}
}
Dictionary<string, Members> dict = new Dictionary<string, Members>();
In this way you have a data model where the name is the key of your dictionary, and
you can use dict["Ana_Salgado"].Age or any of Members property.
Use Dictionary instead of list for example. And then you would be able write something like myDictionary["Ana_Salgado"].Profession
I have two classes.
class Vehicle{
public string VehicleId {get;set;}
public string VinNo {get;set;}
public int ModelYear {get;set;}
public string Make {get;set;}
public bool WaterDamaged {get;set;}
}
class Vins{
public string VinNo {get;set;}
}
I have populated a list of vehicles from the database using this class structure.
So the code looks somewhat like this.
List<Vehicle> vehicles = GetAllVehicles();
Another list I have is sourced from an file. This list contains all the VINs that are water damaged.
I was able to use the same structure for this class as above.
List<Vins> damaged = ReadFile();
List<Vehicles> damagedGoods = new List <Vehicles>();
List<Vehicles> goodGoods = new List <Vehicles>();
I need to create two separate XML files using this info. The first will be called DamagedVehicles_{date} and the next will be GoodVehicles_{date}.
So what I did was write a loop like this.
foreach(var v in damaged)
{
foreach(var v2 in vehicles)
{
if(v.VinNo == v2.VinNo)
{
damagedGoods.Add(new Vehicle{});
}
else
{
goodGoods.Add(new Vehicle{});
}
}
}
This is causing a minor issue. Firstly the goodGoods are getting duplicates, which I later weed out.
Secondly if I receive a list of 80,000 vehicles, it takes a long time for this to process.
Is there some way I can speed the processing and avoid the duplicates?
Your nested foreach is performing a cross product of the two lists. That's...not what you want. Not only is it an inherently expensive operation, but it's results simply aren't in line with what you want.
What you want to do is something like this:
foreach(var vehicle in vehicles)
{
if(damaged.Contains(vehicle.VinN)
{
damagedGoods.Add(new Vehicle{});
}
else
{
goodGoods.Add(new Vehicle{});
}
}
(Note the outer loop is removed entirely.)
This can be further improved due to the fact that List is not particularly efficient at searching. If we use a HashSet to hold onto the damaged vehicles the Contains will be much faster. This is easy enough to do:
HashSet<Vins> damaged = new HashSet<Vins>(ReadFile());
I now have two list box, lstStock and lstSupply. lstSupply consists of
-Pen
-Pencil
-Staple
-Stapler
-Folder
-Notebook
-Eraser
-Marker
and i have two button, one button named btnAdd and another btnRemove.
when i click on btnAdd i want the selected item in lstSupply to be added into lstStock which i have done by
lstStock.Item.Add(lstSupply.SelectedItem);
if i select the same item in lstSupply twice, I want it to be consolidated in lstStock.
for instance, if i select Pen twice, the list box shall give me "Pen x 2" instead of Pen in a line and another Pen in another line.
I got the feeling this is dealing with foreach but i dont really know how to use that.
Okay, so first of all, you're going to need to store something else in lstStock. I'd suggest something like this:
public class StockItem {
public string Name { get; set; }
public int Count { get; set; }
}
Next, I'd suggest that you don't use the .Items field as the actual container where you're storing your stock items. Instead, I'd have a List<StockItem> that you use to populate lstSupply when you refresh.
private List<StockItem> _items = new List<StockItem>();
Then, when you click "add", you do two things:
Iterate through _items to see if there is already a stock item in there of the matching supply. Create one, and add it, if it does not exist.
Find the matching stock item in _items and increment its Count.
To get it to display the way you'd like, we can override ToString() in our StockItem class.:
public class StockItem {
public string Name { get; set; }
public int Count { get; set; }
public override string ToString() {
if (Count > 1)
return Name + " x" + Count;
return Name;
}
}
Finally, whenever any changes are made, you simply re-populate lstStock:
private void RefreshGui() {
lstStock.Items.Clear();
lstStock.Items.AddRange(_items.ToArray());
}
There are plenty of other ways of going about this, but for this simple exercise, this is how I think I would do it.
If you want the code to work without extra coding, you could simply do this:
if (lstSupply.SelectedIndex > -1 && !lstStock.Items.Contains(lstSupply.SelectedItem))
lstStock.Items.Add(lstSupply.SelectedItem);
this way you are sure that you don't add null items and add each item once max.