C# List<T> / List<class> get values - c#

I write to my class different values and I would like to get the values of my class. The Debug outputs shows me:
Value: List.data Index 0
Value: List.data Index 1
How I get the real value of my class properties?
My code example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Diagnostics;
namespace List
{
class data
{
public string name { get; set; }
public Rectangle rect { get; set; }
}
class Program
{
static void Main(string[] args)
{
data dat1 = new data();
List<data> listdat = new List<data>();
dat1.name = "test1";
dat1.rect = new Rectangle(10, 10, 10, 10);
listdat.Add(dat1);
data dat2 = new data();
dat2.name = "test2";
dat2.rect = new Rectangle(20, 20, 20, 20);
listdat.Add(dat2);
data dat3 = new data();
dat3.name = "test3";
dat3.rect = new Rectangle(30, 30, 30, 30);
listdat.Add(dat3);
listdat.RemoveAt(1);
foreach (var item in listdat)
{
//This will yield the proper index that you are currently on
int index = listdat.IndexOf(item);
}
foreach (var item in listdat.Select((value, index) => new { Value = value, Index = index }))
{
//Get the value through item.Value;
var currentValue = item.Value;
//Get the index through item.Index;
int currentIndex = item.Index;
Debug.WriteLine("Value: {0} Index {1}", currentValue, currentIndex);
}
int i = 0;
}
}
}

I´m wondering why you use this weird Select-statement rather than a good old-style for-loop which also gives you the index:
for(int i = 0; i < listdat.Count; i++)
{
var currentValue = listdat[i].Name;
int currentIndex = item.Index;
Debug.WriteLine("Value: {0} Index {1}", currentValue, i);
}
You don´t even have to change your data-class-code, simply access the property (probably name in your case) of your current instance listdat[i] and you´re done.
Btw. the following code is useless as the variable index is reset on every loop but never read:
foreach (var item in listdat)
{
//This will yield the proper index that you are currently on
int index = listdat.IndexOf(item);
}

When you just put an object for printing out it will call the objext's ToString() method, which by default just returns the class' name.
If you want it to output something different you have to override.
You can for example add this to the data class:
public override string ToString()
{
return name;
}

Related

How to loop to add items up to a quantity

I'm trying to make a loop to add 10 items but only add one with the number 10.
List<Contact> listContact;
for (int cuantidade = 0; cuantidade < 10; cuantidade++)
{
listContact = new List<Contact>(cuantidade)
{
new Contact()
{
Name = cuantidade.ToString(),
Number = cuantidade.ToString(),
},
};
}
this.listBoxNames.ItemsSource = listContact;
What am I doing wrong?
Try this:
var contactList= new List<Contact>();
for (int cuantidade = 0; cuantidade < 10; cuantidade++)
{
contactList.Add(new Contact
{
Name = cuantidade.ToString(),
Number = cuantidade.ToString(),
});
}
this.listBoxNames.ItemsSource = contactList;
You need to set the list before the loop. With your current code, at every iteration the list is redefined and resets...
Here is an alternate example pair using Linq
The first just gets 10
The second starts at one point (13) and then gets the next 7
I used a number generator just for the example but it could be any source.
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
// Generate a sequence of integers from 9 to 50
IEnumerable<int> quanityNumbers = Enumerable.Range(9, 50);
// just take the first 10:
List<Contact> contacts = quanityNumbers
.Take(10)
.Select(a => new Contact()
{
Name = a.ToString(),
Number = a.ToString()
}).ToList();
Console.WriteLine($"Hello World contacts has {contacts.Count} items");
foreach (var c in contacts)
{
Console.WriteLine($"contacts has Name: {c.Name} with Number: {c.Number}");
}
//Start at some point and take 7 from there:
List<Contact> contactsFromTo = quanityNumbers
.Skip(13)
.Take(7)
.Select(a => new Contact()
{
Name = a.ToString(),
Number = a.ToString()
}).ToList();
Console.WriteLine($"Hello World contactsFromTo has {contactsFromTo.Count} items");
foreach (var c in contactsFromTo)
{
Console.WriteLine($"contactsFromTo has Name: {c.Name} with Number: {c.Number}");
}
}
public class Contact
{
public string Name { get; set; }
public string Number { get; set; }
}
}

How to select specific fields from dynamic list using LINQ

I am trying to get the some specific fields from dynamic object with is actually a list of any class, this class contains various fields out of those fields I want to select some specific fields using LINQ, The fields which I want to select is also passing by the user. Below is the code that I have tried using System.Linq.Dynamic.
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Linq.Dynamic;
using System.Collections;
private void Test_Click(object sender, EventArgs e)
{
List<RateInfo> lst = new List<RateInfo>();
lst.Add(new RateInfo() { id_country = "IND", id_state = 1, rate = 2.3f });
lst.Add(new RateInfo() { id_country = "IND", id_state = 2, rate = 1.1f });
lst.Add(new RateInfo() { id_country = "IND", id_state = 3, rate = 5.2f });
lst.Add(new RateInfo() { id_country = "IND", id_state = 4, rate = 6.5f });
GetDynamicData(lst, new List<string>() { "id_country", "id_state" });
}
private void GetDynamicData(dynamic list, List<string> fetchFields)
{
var data = ((IEnumerable)list).Cast<dynamic>()
.Select(r => new { r }).AsQueryable();
StringBuilder s = new StringBuilder();
//This is for test only.
//It works, the value of "id_state" and "id_state" getting appended
foreach (var item in data)
{
s.Append(item.r.id_state);
s.Append(",");
s.Append(item.r.id_country);
}
//-----------------------------------------------------
//Select the specific field data from dynamic list
StringBuilder fields = new StringBuilder();
fields.Append("new (");
foreach (var fld in fetchFields)
{
fields.Append("r." + fld);
fields.Append(",");
}
fields.Remove(fields.Length - 1, 1);
fields.Append(")");
//This does not work throws error
//"No property or field 'id_country' exists in type 'Object'"
IQueryable iq = data.Select(fields.ToString());
//For test only to check the value of selected fields
foreach (dynamic item in iq)
{
s.Append(item.id_state);
s.Append(",");
s.Append(item.id_country);
}
}
you can hughly simplify your GetDynamicData method both specifying explicit list type (GetDynamicData(IList<RateInfo> list, ...)) and leaving the list item type generic, in order to reuse the method; with this last approach in mind, you can rewrite the GetDynamicData as follows, obtaining the desired output:
private void GetDynamicData<T>(IEnumerable<T> list, List<string> fetchFields)
{
var fields = $"new ({string.Join(",", fetchFields)})";
var res = list.AsQueryable().Select(fields);
//For test only to check the value of selected fields
foreach (dynamic item in res) {
Console.WriteLine(item.id_state);
Console.WriteLine(item.id_country);
}
}
OUTPUT
1
IND
2
IND
3
IND
4
IND
EXPLANATION
I think the difference is that specifying explicitly the type (through generic T or through RateInfo) you force LINQ to know list items'type; if you use dynamic the IQueryable.ElementType of the IQuqryable instance has value System.Object, so the query fails with the error you've experienced.
You should try using generics:
private void GetDynamicData<T>(IEnumerable<T> list, List<string> fetchFields)
{
var data = list.AsQueryable();

C# Why can't I implicitly convert type 'string' to 'System.Collections.Generic.List<int>'?

I am trying to figure out how to solve the error as stated in the title, which occurs on the bold line within this snippet:
while (textIn.Peek() != -1)
{
string row = textIn.ReadLine();
string[] columns = row.Split('|');
StudentClass studentList = new StudentClass();
studentList.Name = columns[0];
**studentList.Scores = columns[1];**
students.Add(studentList);
}
The previous line of code loads the names just fine since it is not a List within the class I have created, but "Scores" is within a list, however. What modifications would I need to do? These values are supposed to be displayed within a textbox from a text file upon loading the application.
Here is the class in which "Scores" is in (I have highlighted it):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyNameSpace
{
//set the class to public
public class StudentClass
{
public StudentClass()
{
this.Scores = new List<int>();
}
public StudentClass (string Name, List<int> Scores)
{
this.Name = Name;
this.Scores = Scores;
}
public string Name
{ get;
set;
}
//initializes the scores
**public List<int> Scores
{ get;
set;
}**
public override string ToString()
{
string names = this.Name;
foreach (int myScore in Scores)
{ names += "|" + myScore.ToString();
}
return names;
}
public int GetScoreTotal()
{
int sum = 0;
foreach (int score in Scores)
{ sum += score;
}
return sum;
}
public int GetScoreCount()
{ return Scores.Count;
}
public void addScore(int Score)
{
Scores.Add(Score);
}
}
}
You can't just assign a string containing a sequence of numbers to a property of type List<int>.
You need to split the string into seperate numbers, then parse these substrings to get the integers they represent.
E.g.
var text = "1 2 3 4 5 6";
var numerals = text.Split(' ');
var numbers = numerals.Select(x => int.Parse(x)).ToList();
I.e. in your code replace:
studentList.Scores = columns[1];
with:
studentList.Scores = columns[1].Split(' ').Select(int.Parse).ToList();
(Or your own multi-line, more readable/debugable equivalent.)
You'll need to modify the parameter passed to Split() according to how the scores are formatted in your column.
You'll also need to add using System.Linq; at the top if you don't already have it.
As far as the question goes, how would the compiler ever know how to convert the string to a list, when there could be so many string representations of a list. If it was to do this it would be an incredibly slow operation.
Fix
To fix your code you could replace your loop with this.
while (textIn.Peek() != -1)
{
string row = textIn.ReadLine();
StudentClass studentList = new StudentClass();
int index = row.IndexOf("|");
//checking that there were some scores
if (index < 0) {
studentList.Name = row;
continue;
}
studentList.Name = row.Substring(0, index);
studentList.Scores = row.Substring(index + 1).Split('|').Select(int.Parse).ToList();
students.Add(studentList);
}
There are however a number of problems even with this fix.
For one if you were to add another list delimited by '|' it would become increasingly hard for you to parse using this kind of approach.
I suggest instead that you look at serializing your class(es) with something a little more powerful and generic like Json.Net.
Hope this helps.

I'm trying to fill my List<Class> from a text file using C#?

I have a class called cEspecie like this
public class cEspecie
{
private string name;
private int lifetime;
private int movility;
private int deadto;
private int type;
public string Name
{
get
{
return name;
}
set
{
name= value;
}
}
public int Type
{
get
{
return type;
}
set
{
type = value;
}
}
public int LifeTime
{
get
{
return lifetime;
}
set
{
lifetime= value;
}
}
public int Movility
{
get
{
return movility;
}
set
{
movility = value;
}
}
public int DeadTo
{
get
{
return deadto;
}
set
{
deadto = value;
}
}
}
I store some data in a list called
List<cEspecie> list = new List<cEspecie>() {
new cEspecie("Wolf", 100, 10, 0, 0)
new cEspecie("Rabiit", 100, 100, 1, 1),
new cEspecie("Lion", 200, 10, 2, 2),
new cEspecie("Tiger", 300, 10, 3, 3),
};
In one of the process of my program i store all the data inside a text file using this:
using (StreamWriter sr = new StreamWriter(#"../../Archives/TextFilecEspecie.txt"))
{
foreach (var item in list)
{
sr.WriteLine(item.Name);
sr.WriteLine(item.Type);
sr.WriteLine(item.Movility);
sr.WriteLine(item.LifeTime);
sr.WriteLine(item.DeadTo);
}
sr.Close();
}
the result inside "TextFilecEspecie.txt" was this:
Wolf
100
10
0
0
Rabiit
100
100
1
1
Lion
200
10
2
2
Tiger
300
10
3
3
now my real, real problem is ... How can i get back the same data to store it in the same list? I'm using c# and wpf and i really dont find an answer.
Using LINQ, and the Buffer extension method from Microsoft's excellent Ix-Main package.
var species = File.ReadLines("file.txt")
.Buffer(5)
.Select(x => new cEspecie
{
Name = x[0],
Type = int.Parse(x[1]),
Movility = int.Parse(x[2]),
LifeTime = int.Parse(x[3]),
DeadTo = int.Parse(x[4])
});
Buffer(5) will group every 5 lines into an array.
This is what serialization and ISerializable are for.
Here is a quick tutorial that should make it fairly simple.
I might even recommend JSON.Net, which will write it in JSON format so you could more easily create/edit the objects in the file.
You do the same thing only backwards using StreamReader to read the file. I won't get into specifics since I'm guessing you can use the learning experience so consider this a point to the right direction and homework :)
you can do that this way
var list = new List<cEspecie>();
using (StreamReader reader = File.OpenText(filePath))
{
while(!reader.EndOfStream)
{
string name = reader.ReadLine();
int type = int.Parse(reader.ReadLine());
int movility = int.Parse(reader.ReadLine());
int lifeTime = int.Parse(reader.ReadLine());
int deadTo = int.Parse(reader.ReadLine());
list.Add(new cEspecie(name, type, movility, lifeTime, deadTo));
}
}
note that:
int.Parse throw error if the string is not a int, use TryParse the data may not be a int
this work only if the file has the correct number of lines
var list = File.ReadLines("path").Select(x => new cEspecie(x));
in cEspecie constructor you can initialize the object using input line.
Something like this is very simple and should work. Do error checking though.
List<cEspecie> list = new List<Persona>();
string[] readText = File.ReadAllLines(#"../../Archives/TextFilecEspecie.txt");
for(int i=0;i<readText.Length/5;i++)
{
list.Add(new Persona(readText[i*5], readText[i*5+1], readText[i*5+2], readText[i*5+3], readText[i*5+4]));
}

How can I shuffle my list of strings? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Randomize a List<T> in C#
I thought I had my code working but now it seems not. Here's what I have:
public class NoteDetail
{
public NoteDetail()
{
_noteDetails = new List<string>();
}
public IList<string> NoteDetails { get { return _noteDetails; } }
private readonly List<string> _noteDetails;
}
I populate my details like this:
var noteDetail = new NoteDetail ();
noteDetail.NoteDetails.Add("aaa");
noteDetail.NoteDetails.Add("bbb");
noteDetail.NoteDetails.Add("ccc");
Now I want to shuffle so I used this routine:
public static void ShuffleGenericList<T>(IList<T> list)
{
//generate a Random instance
var rnd = new Random();
//get the count of items in the list
var i = list.Count();
//do we have a reference type or a value type
T val = default(T);
//we will loop through the list backwards
while (i >= 1)
{
//decrement our counter
i--;
//grab the next random item from the list
var nextIndex = rnd.Next(i, list.Count());
val = list[nextIndex];
//start swapping values
list[nextIndex] = list[i];
list[i] = val;
}
}
My problem is that I am not sure how to do the shuffle. I have tried the following but it gives:
Error 237 Argument 1: cannot convert from 'System.Collections.Generic.IList' to 'System.Collections.Generic.IList<.Storage.Models.NoteDetail>'
Sort.ShuffleGenericList<NoteDetail>(noteDetail.NoteDetails);
Can anyone see what I am doing wrong. It all looks okay to me and I can't see why I should get this error :-(
You should change this:
Sort.ShuffleGenericList<NoteDetail>(noteDetail.NoteDetails);
To:
Sort.ShuffleGenericList<string>(noteDetail.NoteDetails);
Because noteDetail.NoteDetails is a List<string>, not a List<NoteDetail>.
You are using the wrong type to parametrize your generic method, do this instead:
Sort.ShuffleGenericList(noteDetail.NoteDetails);
or more explicit (but unneccessary):
Sort.ShuffleGenericList<string>(noteDetail.NoteDetails);
You were passing NoteDetail as type, rather than string - that won't work.
I took your code and threw it into VS. The below execustes okay with a few small modifications:
using System;
using System.Collections.Generic;
using System.Linq;
namespace MsgBaseSerializeationTest
{
class StackOverflow
{
public void Test()
{
var noteDetail = new NoteDetail<string>();
noteDetail.NoteDetails.Add("aaa");
noteDetail.NoteDetails.Add("bbb");
noteDetail.NoteDetails.Add("ccc");
NoteDetail<string>.ShuffleGenericList(noteDetail);
}
}
public class NoteDetail<T> : List<T>
{
public NoteDetail()
{
_noteDetails = new List<string>();
}
public IList<string> NoteDetails { get { return _noteDetails; } }
private readonly List<string> _noteDetails;
public static void ShuffleGenericList(IList<T> list)
{
//generate a Random instance
var rnd = new Random();
//get the count of items in the list
var i = list.Count();
//do we have a reference type or a value type
T val = default(T);
//we will loop through the list backwards
while (i >= 1) {
//decrement our counter
i--;
//grab the next random item from the list
var nextIndex = rnd.Next(i, list.Count());
val = list[nextIndex];
//start swapping values
list[nextIndex] = list[i];
list[i] = val;
}
}
}
}

Categories