Finding strings using LINQ [duplicate] - c#

This question already has answers here:
Why writing items to console writes only namespace and class name instead of data? [duplicate]
(5 answers)
Closed 5 years ago.
After some research into C# and some test with LINQ with easy examples. I wanted to apply this knowledge into my problem.
My DataStructure as seen from the variable screen (Visual Studio)
- wm
- Nations
- [0]
- Name "USA"
- stockpile
- [0]
- Name "Coal"
- Quantity "quantity"
- Value "value"
- [1] //Same as above
My attempt to access "Coal" has been:
var result = wm.Nations.Find(r => r.Name == "USA")
Console.WriteLine(result + " Result");
But only returns [EconomyTest.NationBuilder] which is an object. How can i extract a string from that object or at least point to USA and access to the stockpile?
Edit1: Data Structure Declaration
//Declarations of Lists
public List<ResourceTemplate> stockpile = new List<ResourceTemplate>();
public List<Money> money = new List<Money>();
public List<PopulationTemplate> population = new
List<PopulationTemplate>();
public NationBuilder(string name)//Constructor
{
this.Name = name;
stockpile = new List<ResourceTemplate>();
money = new List<Money>();
population = new List<PopulationTemplate>();
}
//World Market (Where the actual storage happens)
public WorldMarket()//Constructor
{
//Declaration list
Nations = new List<NationBuilder>();
}
internal List<NationBuilder> Nations {get; set;}
public void AddToWorldMarket(NationBuilder nation)
{
Nations.Add(nation);
}
//Finally how it is managed/used:
WorldMarket wm = new WorldMarket();//Helps with adding those newly
created nations into a List
foreach (string name in NationNames)
{
NationBuilder nation = new NationBuilder(name);//Creates new
Objects nations and used the name provided before
nation.AddResource("Coal", 500, 10);
nation.AddResource("Water", 100, 10);
nation.AddMoney(100);
nation.AddPopulation(1000);
wm.AddToWorldMarket(nation);
Edit2: Function asked in the comments
public void AddResource(string itemName, int quantity, float
value)//Adds Resources to the stockpile
{
stockpile.Add(new ResourceTemplate {Name = itemName, Quantity =
quantity, Value = value });
}

Your entire result variable is just being written out to the console as it is just having its ToString method called to render it, I think what you want is:
Console.WriteLine(result.Name + " Result");
Optionally, if you want the object to show more when rendered to the console, you can override ToString yourself.
public override string ToString()
{
return this.Name + ", stockpile count: " + this.stockpile.Length;
}

Just specify the Name
Console.WriteLine(result.Name + " Result");
To access to stockpile you can iterate it;
foreach (var stock in result.stockpile)
{
//stock.Name
}

Related

How to set multiple values of properties inside an object in C#?

Please tell me how to add multiple properties inside an single object.
like- if there is a class having 5 variables defined with get and set.
I want to add like 2 values for each variable through a single object of that class like
class Info{
int count{get , set,};
string name{get , set,};
string Dept {get , set,};
string Address {get , set,};
long contact {get , set,};
info obj =new Info();
/* Now after this I want to take 2 rows like
in first row I want to set it's values through a single object
Count=1,name="Robert",Dept="Computer",Address="India",Contact=434343
in row 2nd row
Count=1,name="Robbin",Dept="Electronic",Address="Colombo",Contact=54545
*/
}
/// Now please explain me how to set like above two rows values inside one object.. ///
I think what you're looking for is inline object initialization: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/how-to-initialize-objects-by-using-an-object-initializer
You can write it on a single line but the code would look better if you break it into multiple lines:
Info infoObj = new Info
{
Count = 1,
Name = "Robert",
Dept = "Computer",
Address = "India",
Contact = 434343
};
If what you mean is initializing a class with set properties, look at Peter Sandor's answer.
if you're looking to declare a class with a set of fields that'll be filled with values upon initialization without giving them values (aka. default values), then this might help:
class Info
{
public int count = 5;
pubic string name = "Robert"
}
Please note that these are fields and not properties though, if you'd like to do the same with properties instead of fields, i'd suggest doing this with propfull:
private int count = 5;
public int Count
{
get { return count; }
set { count = value; }
}
Hope this helps!
Instead of creating an instance of the Info class, make a List of Info:
List<Info> aSingleObj = new List<Info>();
Now you can add as many things to the single object:
aSingleObj.add(new Info { Count = 1, name = "Robert", Dept = "Computer", Address = "India", contact = "434343" });
aSingleObj.add(new Info { Count = 1, name = "Robbin", Dept = "Electronic", Address = "Colombo", contact = "54545" });
To distinguish between them, and print the output, do:
Console.WriteLine($"First row: Count = {aSingleObj[0].Count}, Name = {aSingleObj[0].name}, Department: {aSingleObj[0].Dept}, Address = {aSingleObj[0].Address}, Contact = {aSingleObj[0].contact}");
and for second row:
Console.WriteLine($"Second row: Count = {aSingleObj[1].Count}, Name = {aSingleObj[1].name}, Department: {aSingleObj[1].Dept}, Address = {aSingleObj[1].Address}, Contact = {aSingleObj[1].contact}");

Sorting List Array based on an index of array

I want to sort a List Array on the basis of an array item.
I have a List Array of Strings as below:
List<String>[] MyProjects = new List<String>[20];
Through a loop, I have added five strings
(Id, Name, StartDate, EndDate, Status)
to each of the 20 projects from another detailed List source.
for(int i = 0; i<20; i++){
MyProjects[i].Add(DetailedProjectList.Id.ToString());
MyProjects[i].Add(DetailedProjectList.Name);
MyProjects[i].Add(DetailedProjectList.StartDate);
MyProjects[i].Add(DetailedProjectList.EndDate);
MyProjects[i].Add(DetailedProjectList.Status)}
The Status values are
"Slow", "Normal", "Fast", "Suspended" and "" for unknown status.
Based on Status, I want to sort MyProject List Array.
What I have done is that I have created another List as below
List<string> sortProjectsBy = new List<string>(){"Slow", "Normal", "Fast", "", "Suspended"};
I tried as below to sort, however unsuccessful.
MyProjects = MyProjects.OrderBy(x => sortProjectsBy.IndexOf(4));
Can anyone hint in the right direction. Thanks.
I suggest you to create class Project and then add all the fields inside it you need. It's much nicer and scalable in the future. Then create a List or an Array of projects and use the OrderBy() function to sort based on the field you want.
List<Project> projects = new List<>();
// Fill the list...
projects.OrderBy(project => project.Status);
The field Status has to be a primitive type or needs to implement the interface IComparable in order for the sorting to work. I suggest you add an enum for Status with int values.
First consider maybe to use Enum for status and put it in a different file lite (utils or something) - better to work like that.
enum Status {"Slow"=1, "Normal", "Fast", "", "Suspend"}
Now about the filtering you want to achieve do it like this (you need to tell which attribute of x you are referring to. In this case is status)
MyProjects = MyProjects.OrderBy(x => x.status == enum.Suspend);
Read about enums :
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/enum
Read about lambda expressions :
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions
First of all, storing project details as List is not adivisable. You need to create a Custom Class to represent them.
For example,
public class DetailedProjectList
{
public string Name {get;set;}
public eStatus Status {get;set;}
// rest of properties
}
Then You can use
var result = MyProjects.OrderBy(x=> sortProjectsBy.IndexOf(x.Status));
For example
List<string> sortProjectsBy = new List<string>(){"Slow", "Normal", "Fast", "", "Suspended"};
var MyProjects= new List<DetailedProjectList>{
new DetailedProjectList{Name="abc1", Status="Fast"},
new DetailedProjectList{Name="abc2", Status="Normal"},
new DetailedProjectList{Name="abc3", Status="Slow"},
};
var result = MyProjects.OrderBy(x=> sortProjectsBy.IndexOf(x.Status));
Output
abc3 Slow
abc2 Normal
abc1 Fast
A better approach thought would be to use Enum to represent Status.
public enum eStatus
{
Slow,
Normal,
Fast,
Unknown,
Suspended
}
Then your code can be simplified as
var MyProjects= new List<DetailedProjectList>{
new DetailedProjectList{Name="abc1", Status=eStatus.Fast},
new DetailedProjectList{Name="abc2", Status=eStatus.Normal},
new DetailedProjectList{Name="abc3", Status=eStatus.Slow},
};
var result = MyProjects.OrderBy(x=> x.Status);
Ok so you have a collection of 20 items. Based on them you need to create a list of strings(20 DetailedProjectList items).
What you can do to solve your problem is to SORT YOUR COLLECTION before you create your list of strings. In this way your list of strings will be sorted.
But your code is not optimal at all. So you should concider optimization on many levels.
Lets say you have ProjectDetail class as follow:
private class ProjectDetail
{
public int Id {get;set;}
public string Name {get;set;}
DateTime StartDate {get;set;} = DateTime.Now;
DateTime EndDate {get;set;} = DateTime.Now;
public string Status {get;set;}
public string toString => $"{Id} - {Name} - {StartDate} - {EndDate} - {Status}";
}
Notice that I have added a toString attribute to make things easier, and I also have added default values.
Then your program could be like:
static void Main(string[] args)
{
var projectDetails = MockProjectItems();
Console.WriteLine("Before sortig:");
foreach (var item in projectDetails)
{
Console.WriteLine(item.toString);
}
var myProjects = projectDetails.OrderBy(p => p.Status).Select(p => p.toString);
Console.WriteLine("\n\nAfter sorting:");
foreach (var item in myProjects)
{
Console.WriteLine(item);
}
}
where the helper method is
private static List<ProjectDetail> MockProjectItems()
{
var items = new List<ProjectDetail>(20);
for(int i = 0; i < 20 ; i += 4){
items.Add(new ProjectDetail{Id = i, Name = "RandomName "+i, Status = "Slow"});
items.Add(new ProjectDetail{Id = i+1, Name = "RandomName "+(i+1), Status = "Normal"});
items.Add(new ProjectDetail{Id = i+2, Name = "RandomName "+(i+2), Status = "Fast"});
items.Add(new ProjectDetail{Id = i+3, Name = "RandomName "+(i+3), Status = "Suspended"});
}
return items;
}
Then your program should print the following:

Show different objects by double clicking listbox with same name

Currently I'm working on a school project where I have this class members.
The listbox shows the propeties names as in Members.Name.
The problem I have is members with the same name shows the same information in the output textbox. I kinda need a different solution let me paste in my.
public void OutputMember()
{
searchResult = MemberSearch.ByName(Program.memberList, lbmembers.Text);
foreach (Members member in searchResult)
{
tboutput.Text = string.Format("Medlemsnr {0}" +
"Namn: {1}\r\n" +
"Eftername: {2}\r\n" +
"Personnummer: {3}\r\n" +
"Adress: {4}\r\n" +
"Email: {5}\r\n" +
"Tele:{6}\r\n\r\n\r\n",member.MemberNr, member.Name, member.SurName, member.BirthYear.outStringWithId(),
member.Adress, member.Email, member.Tele);
So I understand that the problem of this is the parameters.
I just send a list of members and just the name in text.
public static List<Members> ByName(List<Members> memberList, string member)
{
List<Members> searchList = new List<Members>();
for (int i = 0; i < memberList.Count; i++)
{
if (memberList[i].Name.Equals(member))
{
searchList.Add(memberList[i]);
}
}
return searchList;
so the questions remains how do I view the "right" object in the output textbox by double clicking one of three equal names in the list.
You have not coded what you expect the program to do.
You expect the program to display the related Member based on its position in the list.
But you have coded a search method that returns the Member based on a name match, of which there are possible duplicates.
You are also returning multiple items from the list when you only need 1, and are needlessly looping through all results only to return the last one.
You just need:
public void OutputMember()
{
member = Program.memberList[lbmembers.SelectedIndex]);
tboutput.Text = string.Format("Medlemsnr {0}" +
"Namn: {1}\r\n" +
"Eftername: {2}\r\n" +
"Personnummer: {3}\r\n" +
"Adress: {4}\r\n" +
"Email: {5}\r\n" +
"Tele:{6}\r\n\r\n\r\n",member.MemberNr, member.Name, member.SurName, member.BirthYear.outStringWithId(),
member.Adress, member.Email, member.Tele);
}

C# - Editing Listbox Items

I'm making an app in Windows Forms that simulates a Point of Sales. I'm creating now the part where the user clicks on a product button and it adds to a listbox an item like this: "'Quantity' - 'Name of the product' - 'cost'".
When the button is clicked again is supposed to edit the item like this: "'Quantity+1' - 'Name of the product' - 'cost*2'".
However it just add another item with that information.
So far, my code is the following:
private void bprod1_Click(object sender, EventArgs e)
{
MySqlCommand cmdp1 = new MySqlCommand("SELECT preco_unitario FROM produtos where designacao='" + bprod1.Text + "';", mConn);
mConn.Open();
MySqlDataReader drp1 = cmdp1.ExecuteReader();
drp1.Read();
string getpreco1 = drp1["preco_unitario"].ToString();
mConn.Close();
quant1 = quant1 + 1;
var preco1tot = quant1 * Convert.ToDecimal(getpreco1);
var text1 = quant1.ToString() + " - " + bprod1.Text + " - " + preco1tot.ToString();
listvenda.Items.Add(text1);
}
bprod1 is my button. quant1 starts with value 0. getpreco1 is the value I get from the database (product's cost).
My objective is, when clicked the second time and so on, increase the quantity and add the cost without creating a new item.
I could just delete the item and add another one with the new info, but I want the item to be in the same place as the other, and not on the end of the list.
I appreciate any suggestions and help.
Hope you guys understand what I intend to do.
This line:
listvenda.Items.Add(text1);
is why you're seeing a new item every single time. A mature application would be more likely to use either private class or Model approaches.
Create a new class file within the same namespace and call it something. See below:
public class myProduct
{
public int Quantity {get; set;}
public int Name {get; set;}
public double Price {get; set;}
public myProduct(string name)
{
this.Quantity = 1; this.Name = name; this.Price = 0;
}
public override string ToString()
{
return this.Quantity.ToString() + "-" + this.Name + "-" +
(this.Price * this.Quantity).ToString(c,
CultureInfo.CurrentCulture);
}
}
Now, where you were just adding values, you can check to see if the line exists, and if it does, operate on it. Otherwise, add a new line. Don't bother with ToString() methods and such, as you can actually populate your listbox with a list of the new class! It will call the ToString() method when displaying values.
List<myProduct> listvendaBind = new List<myProduct>();
///insert code here to build your list from the database if you havent already. Otherwise, skip this step so you dont overwrite your list
//now the code for modification
var x = listvendaBind.Where(t => t.Name == newProduct.Name).FirstOrDefault();
if(x.Count() > 0 && (x != null)
listvendaBind[listvendaBind.IndexOf(x[0])].Quantity++;
else
listvendaBind.Add(newProduct);
listvenda.DataSource = listvendaBind;
This is untested, as I'm working on another project at the moment, but should serve as proof of concept.
This is only for learning and I do not recommended using it outside testing environment but you can do something like this:
insetad of
listvenda.Items.Add(text1);
do this:
bool notFound = true;
for(int i=0; i<listvenda.Items.Count; i++)
{
if(((string)listvenda.Items[i]).Contains(" - " + bprod1.Text + " - "))
{
listvenda.Items[i] = text1;
notFound = false;
break;
}
}
if(notFound)
listvenda.Items.Add(text1);
but as I said it should only be temporary solution. Instead of this use CDove solution

Removing duplicate objects from a list [duplicate]

This question already has answers here:
Remove duplicates from a List<T> in C#
(32 answers)
Closed 7 years ago.
I am currently working on a project and have hit a snag.
I'm taking in an unformatted string[] of football teams and I'm trying to filter the data and return it in a more orgainised format.
I'm fine with most of it (splitting the string to get the relevant values and sorting the format) except i have created a Team object which holds most of this data and as i loop through the original string i create a new team object each time i see a team name. Then i check to see if i've seen that object before and if i have i don't create a new object. After creating the Team or skipping that part i add the relevant info to the team object and continue.
My issue is the list i'm using to hold the final team info has many duplicates mean my check to see if the object exists or not doesn't work. The code is :
After splitting string,
List<Team> teams = new List<Team>();
for (int i = 1; i <= matches.Length - 1; i++)
{
string fullStr = matches[i];
string[] score = fullStr.Split(',');
string[] team1 = score[0].Split('!');
string team1Name = team1[0];
Team teams1 = new Team(team1Name);
if (teams.Contains(teams1) != true)
{
teams.Add(teams1);
}
string team1Score = team1[1];
int team1ScoreInt = int.Parse(team1Score);
string[] team2 = scores[1].Split('!');
string team2Name = team2[1];
Team teams2 = new Team(team2Name);
if (!teams.Contains(teams2))
{
teams.Add(teams2);
}
When i print the list i get the format i want but multiple Germanys etc. And only the score etc of that 1 game rather than them all adding to 1 Germany Team object.
Any ideas how i can stop the duplicates and maintain using only the 1 Team object every time i see that team name?
Thanks
You can implement IEqualityComparer for Team class and check equality of objects based on its values. Something like below.
using System.Collections.Generic;
public class Team{
public string Name {get;set;}
public int score {get;set;}
}
//Create some dummy data
public List<Team> lstTeam = new List<Team>{
new Team{Name="A", score=1},
new Team{Name="A", score=1},
new Team{Name="B", score=1},
new Team{Name="C", score=2},
new Team{Name="A", score=2},
new Team{Name="C", score=2}
};
List<Team> lstDistictTeams = lstTeam.Distinct<Team>(new DistinctComparer()).ToList();
foreach(Team t in lstDistictTeams)
{
Console.WriteLine("Team {0} has Score {1}",t.Name,t.score);
}
//This class provides a way to compare two objects are equal or not
public class DistinctComparer : IEqualityComparer<Team>
{
public bool Equals(Team x, Team y)
{
return (x.Name == y.Name && x.score == y.score); // Here you compare properties for equality
}
public int GetHashCode(Team obj)
{
return (obj.Name.GetHashCode() + obj.score.GetHashCode());
}
}
Here is running example : http://csharppad.com/gist/6428fc8738629a36163d
Looks like the problem is you're creating a new Team object with the name of the team for each result.
When you then compare against the list to see if it is contained, you're checking to see if there's a reference to that object in the list, and as you've just created it, there won't be, so every Team object you create will be added to the list.
You'll need to check whether the list contains a Team object with the name, rather than just check for the instance of the object.

Categories

Resources