C# How to make a list out of IEnumerable - c#

I'm currently playing with TvDbSharper (https://github.com/HristoKolev/TvDbSharper) and i have a question about IEnumerable.
What i'm trying to do is get all the Id for a given series and then add the result in a listView.
This code gives me the first Id in the list:
const int SeriesId = 78804;
var tasks = new List<Task<TvDbResponse<BasicEpisode[]>>>();
var firstResponse = await client.Series.GetEpisodesAsync(SeriesId, 1);
for (int i = 2; i <= firstResponse.Links.Last; i++)
{
tasks.Add(client.Series.GetEpisodesAsync(SeriesId, i));
}
var results = await Task.WhenAll(tasks);
var episodes = firstResponse.Data.Concat(results.SelectMany(x => x.Data));
epsListview.View = View.Details;
epsListview.Columns.Add("Episode", 100);
string[] arr = new string[4];
ListViewItem itm;
arr[0] = episodes.First().Id.ToString();
itm = new ListViewItem(arr);
epsListview.Items.Add(itm);
but what i want is to make a new line in the epsListview for each id available.
I never used IEnumerable and i'm still very novice using c#, i've been stuck with this problem for over a week now. can anyone help me with this ?
Thanks!!

It looks like you're wanting to build an array of IDs from an IEnumerable of episodes, and add that array to a single ListViewItem. This should do that.
string[] arr = episodes.Select(episode => episode.Id.ToString()).ToArray()
ListViewItem itm = new ListViewItem(arr);
epsListview.Items.Add(itm);

Related

c# trying to achieve more than ten list in single foreach

i have more than 10 list and i want to put it inside single foreach i tried (Tuple.Create) but it is limited for only 7 items and also tried (from in) the result of first item from it is repeated.
List<string> ALLmlist1 = new List<string>();
List<string> ALLmlist2 = new List<string>();
List<string> ALLmlist3 = new List<string>();
List<string> ALLmlist4 = new List<string>();
List<string> ALLmlist5 = new List<string>();
List<string> ALLmlist6 = new List<string>();
List<string> ALLmlist7 = new List<string>();
List<string> ALLmlist8 = new List<string>();
List<string> ALLmlist9 = new List<string>();
List<string> ALLmlist10 = new List<string>();
List<string> ALLmlist11 = new List<string>();
List<string> ALLmlist12 = new List<string>();
List<string> ALLmlist13 = new List<string>();
List<string> ALLmlist14 = new List<string>();
List<string> ALLmlist15 = new List<string>();
foreach(var item in all15list)
{
var i1 = item.Item1;
var i2 = item.Item2;
{
trying to look like this, hope you guys have other option thanks.
edit : im trying to get each list result in one foreach.
sorry im bad at english
You should probably use a nested list. I.e.
var outerList = new List<List<string>>();
for(var outerIndex = 0; outerIndex < outerList.Count; outerIndex++){
var innerList = outerList[outerIndex];
for(var innerIndex = 0; innerIndex < innerList.Count; innerIndex++){
var value = innerList[innerIndex];
//Do something with each value
}
}
If you have a bunch of separate lists and want to create a nested list you can use a collection initializer:
var outerList = new List<List<string>>(){
ALLmlist1 ,
ALLmlist2,
...
} ;
That said, keeping a bunch of list in that way is somewhat of a design smell. Usually it would represent something, like objects, 2D data, or something else. And if so it might be better to use some kind of specialized type that better represent the data.
Is this what you want?
var minCount = new List<int>
{
ALLmlist1.Count,
ALLmlist2.Count,
...
ALLmlist15.Count,
}.Min();
for (var i = 0; i < minCount; i++)
{
var i1 = ALLmlist1[i];
var i2 = ALLmlist2[i];
...
var i15 = ALLmlist15[i];
}

Splitting a string into 3 different arrays

I am receiving a string reply from serial port and this reply contains 3 different value. Every value is separated with ';'.
For example;
10;155.4587;0.01
I need to separate these values and add to a Listview box.
I've found examples of Split(';') function but i think it is not possible to assign split values to different arrays.
Is there any way to perform this extraction with using/not using split() function?
Thanks in advance for any help.
Assuming an array of input strings...
string[] a1 = new string[] {
"10; 155.4587; 0.01",
"20; 255.4587; 0.02",
"30; 355.4587; 0.03",
};
List<string> r1 = new List<string>();
List<string> r2 = new List<string>();
List<string> r3 = new List<string>();
foreach (string t1 in a1)
{
string[] t2 = t1.Split(";");
r1.Add(t2[0]);
r2.Add(t2[1]);
r3.Add(t2[2]);
}
There's a wide variety of methods to doing this, you could use a Regex to delimit each item and use Lambda functions.
You could do something more basic like manipulating the below drawn-out example:
string s = "10;155.4587;0.01";
string[] a = new String[1];
string[] b = new String[1];
string[] c = new String[1];
string[] z = s.Split(';');
for(int i=0; i< z.Length; i++)
{
switch(i)
{
case 0:
a[0] = z[i];
break;
case 1:
b[0] = z[i];
break;
case 2:
c[0] = z[i];
break;
}
}
Console.WriteLine(a[0] + ' ' + b[0] + ' ' + c[0]);
The above illustrates how to manipulate elements but doesn't scale exactly well you may wish to pursue the anonymous route with the first comment using lambdas (see mukesh kudi's answer).
You can get this with help of linq...
string s = "10;155.4587;0.01";
var arrList = s.Split(';').Select(x => new string[] { x }).ToArray();
Here arrList contains three arrays. but i am not sure how this will help you. if you want to bind this result with ListView you have to traverse this collection and get each array value and bind to listview. you can do this with single array by traverse it's index's.
EDIT
To add just one list view item use:
var s = "10;155.4587;0.01";
var values = s.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
var listViewItem = new ListViewItem(values[0]);
listViewItem.SubItems.Add(values[1]);
listViewItem.SubItems.Add(values[2]);
listView1.Items.Add(listViewItem);
Assuming you have multiple strings to populate the listBox, try:
ListView listView1 = new ListView();
listView1.Bounds = new Rectangle(new Point(10, 10), new Size(300, 200));
listView1.View = View.Details;
listView1.GridLines = true;
listView1.Columns.Add("TD");
listView1.Columns.Add("AD");
listView1.Columns.Add("CT", -2);
var sValues = new string[] { "10;155.4587;0.01", "11;156.4587;0.02", "12;157.4587;0.03" };
var values = sValues.Select(x => x.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
.Select(x =>
{
var listViewItem = new ListViewItem(x[0]);
listViewItem.SubItems.Add(x[1]);
listViewItem.SubItems.Add(x[2]);
return listViewItem;
});
listView1.Items.AddRange(values.ToArray());
Thanks for all the help.
With the suggestion of #Captain Wibble, i successfully decoded my replies and add to Listview item.
Here is what i did for anyone in same trouble;
First i added my data packages "\r\n"
10;12.2345;0.01\r\n
I used;
serial.ReadLine()
Function to receive incoming data.
To decode and store the data into a listview object i use;
var s = text;
string[] a = new String[3];
//string[] b = new String[1];
//string[] c = new String[1];
string[] z = s.Split(';');
for (int i = 0; i < z.Length; i++)
{
switch (i)
{
case 0:
a[0] = z[i];
break;
case 1:
a[1] = z[i];
break;
case 2:
a[2] = z[i];
break;
}
}
itm = new ListViewItem(a);
listView5.Items.Add(itm);

Assist with simple count out of a list

I'm trying to count the number of people marked as Break in a column in a list.
currently when I run my foreach loop (the one at the bottom) to count the number of breaks listed it throws the error message cannot convert type char to string. I understand that my class of NewAgent does not contain all string values but I'm only trying to reference one string. I need a way to count the number of times break appears in my list. Break would appear under newAgent.auxreason
public List newAgentList;
List<NewAgent> newAgentList = new List<NewAgent>();
NewAgent newAgents = new ScoreBoardClientTest.NewAgent();
foreach (var item in e.CmsData.Agents)
{
newAgents.AgentName = item.AgName;
newAgents.AgentExtension = item.Extension;
newAgents.AgentDateTimeChange = ConvertedDateTimeUpdated;
newAgents.AuxReasons = item.AuxReasonDescription;
newAgents.LoginIdentifier = item.LoginId;
newAgents.AgentState = item.WorkModeDirectionDescription;
var timeSpanSince = DateTime.Now - item.DateTimeUpdated;
newAgents.AgentDateTimeStateChange = timeSpanSince;
newAgentList.Add(newAgents);
}
int breakCount = 0;
foreach(string s in newAgents.AuxReasons)
{
if (s != null && s.StartsWith("Break")) breakCount++;
}
Try this:
int breakCount = 0;
foreach(var agent in newAgentList)
{
if (!string.IsNullOrEmpty(agent.AuxReasons) && agent.AuxReasons.StartsWith("Break"))
breakCount++;
}
You should also create new object in each iteration:
foreach (var item in e.CmsData.Agents)
{
NewAgent newAgents = new ScoreBoardClientTest.NewAgent();
newAgents.AgentName = item.AgName;
newAgents.AgentExtension = item.Extension;
newAgents.AgentDateTimeChange = ConvertedDateTimeUpdated;
newAgents.AuxReasons = item.AuxReasonDescription;
newAgents.LoginIdentifier = item.LoginId;
newAgents.AgentState = item.WorkModeDirectionDescription;
var timeSpanSince = DateTime.Now - item.DateTimeUpdated;
newAgents.AgentDateTimeStateChange = timeSpanSince;
newAgentList.Add(newAgents);
}
First, you need to put NewAgent newAgents = new ScoreBoardClientTest.NewAgent(); inside your first foreach loop because right now you are working with reference to the same object and if you update any property of this object in one place it will be updated for the entire list.
Second, you need to work with newAgentList in the second loop and not with newAgents (this is why you are seeing the exception since you are going trough chars inside the string instead of going trough elements of a list).
This should work:
public List newAgentList;
List<NewAgent> newAgentList = new List<NewAgent>();
foreach (var item in e.CmsData.Agents)
{
NewAgent newAgents = new ScoreBoardClientTest.NewAgent();
newAgents.AgentName = item.AgName;
newAgents.AgentExtension = item.Extension;
newAgents.AgentDateTimeChange = ConvertedDateTimeUpdated;
newAgents.AuxReasons = item.AuxReasonDescription;
newAgents.LoginIdentifier = item.LoginId;
newAgents.AgentState = item.WorkModeDirectionDescription;
var timeSpanSince = DateTime.Now - item.DateTimeUpdated;
newAgents.AgentDateTimeStateChange = timeSpanSince;
newAgentList.Add(newAgents);
}
int breakCount = 0;
foreach(string s in newAgentList.AuxReasons)
{
if (!string.IsNullOrWhiteSpace(s.AuxReasons) && s.AuxReasons.StartsWith("Break")) breakCount++;
}
Ok, first of all, we're doing something bad in the loop.
You're declaring newAgents, and setting it over and over again, so it will always have values equal to the last item in e.CmsData.Agents. For example, if you have a list, and the AgNames of the items in the list are:
Bob
Michael
James
newAgents is always going to have an AgentName of "James" when the loop completes, because it's declared out of scope of the loop. Fix this by moving the declaration of your NewAgent placeholder inside the scope of the loop, like following:
List<NewAgent> newAgentList = new List<NewAgent>();
foreach (var item in e.CmsData.Agents)
{
NewAgent newAgents = new ScoreBoardClientTest.NewAgent();
// perform your data transforms
newAgentList.Add(newAgents);
}
That will make it so you're actually adding elements to your list that correspond to the data you're trying to manipulate, and there is no need for that variable to exist outside the loop.
Are you trying to count the number of reasons per Agent in the list, or are you trying to count all "Break" reasons in all agents? The reason I ask is again, you're doing your last foreach loop on your iterator variable, after your iteration process has completed.
To count all elements' breaks, do this instead of your second loop:
int count = newAgentList.Sum(agent =>
agent.AuxReasons.Count(reasons =>
!string.IsNullOrEmpty(reasons) && reasons.StartsWith("Break")));
If you want to count the iterator while you're operating on it, use the inner lambda function in your first loop like this:
foreach (var item in e.CmsData.Agents)
{
// other logic from above
int count = newAgents.AuxReasons.Count(r =>
!string.IsNullOrEmpty(r) && r.StartsWith("Break");
// do something with count before loop ends
}
If you do this latter version, you're going to need to do something with that count before the loop's iteration completes or it will be lost.
If all this is unclear, here's a fully modified version of your code:
List<NewAgent> newAgentList = new List<NewAgent>();
foreach (var item in e.CmsData.Agents)
{
NewAgent newAgents = new ScoreBoardClientTest.NewAgent();
newAgents.AgentName = item.AgName;
newAgents.AgentExtension = item.Extension;
newAgents.AgentDateTimeChange = ConvertedDateTimeUpdated;
newAgents.AuxReasons = item.AuxReasonDescription;
newAgents.LoginIdentifier = item.LoginId;
newAgents.AgentState = item.WorkModeDirectionDescription;
var timeSpanSince = DateTime.Now - item.DateTimeUpdated;
newAgents.AgentDateTimeStateChange = timeSpanSince;
newAgentList.Add(newAgents);
}
int breakCount = newAgentList.Count(agent =>
!string.IsNullOrEmpty(agent.AuxReasons) && agent.AuxReasons.StartsWith("Break"));
first move
NewAgent newAgents = new ScoreBoardClientTest.NewAgent();
into the first loop so the newAgents will be new when you add it
second , the second foreach is on a string so it gives you list of chars

arraylist with object type

hi i using arraylist and storing simple object array in that , my sample code snipt
ArrayList rows = new ArrayList();
object[] objs = new object[3];
objs[0] = 1;
objs[1] = "dilip";
objs[2] = 27;
rows.Add(objs);
objs = new object[3];
objs[0] = 2;
objs[1] = "lucky";
objs[2] = 42;
rows.Add(objs);
objs = new object[3];
objs[0] = 3;
objs[1] = "user";
objs[2] = 46;
rows.Add(objs);
objs = new object[3];
objs[0] = 4;
objs[1] = "testing";
objs[2] = 76;
rows.Add(objs);
objs = new object[3];
objs[0] = 5;
objs[1] = "trying";
objs[2] = 44;
rows.Add(objs);
How can i apply asc or desc sorting on any index of object
for example sorting based on name which index 1 or sorting based on age which index 2 ..
please provide any suggestion .
Thanks ..
Most of LINQ methods will work with a strongly typed IEnumerable<T> interface.
Use OfType method like this rows.OfType<object[]>().OrderBy(x => x[1])
Though the way you approach your data structures will quickly make the code unmaintainable. You'd better consider using classes to reflect your data.
You need to have comparer to sort your ArrayList type. In your case it would look something like this:
public class MyComparer : IComparer
{
int IComparer.Compare(Object x, Object y)
{
int sortingIndex = 1;
var xUnbox = x as object[];
var yUnbox = y as object[];
return ((new CaseInsensitiveComparer()).Compare(yUnbox[sortingIndex], xUnbox[sortingIndex]));
}
}
Having this, you can now sort your ArrayList:
var comparer = new MyComparer();
rows.Sort(comparer);
foreach (object[] line in rows)
{
Console.WriteLine(line[1]);
}
This example would sort your ArrayList by index 1.
Although I would highly recommend using strongly typed collection, like List<YourType> instead, since then you could just Linq order that.
Is there a reason you could not use List<object[]> instead of using ArrayList?
For example:
List<object[]> rows = new List<object[]>();
object[] objs = new object[3];
objs[0] = 1;
objs[1] = "dilip";
objs[2] = 27;
rows.Add(objs);
var query = rows.Where(r => (string)r[1] == "dilip");
You could then do all your various sorting, etc.
var query = rows
.OrderBy(r => (int)r[0])
.OrderBy(r => (string)r[1])
.OrderByDescending(r => (int)r[2]);

How to add non-duplicate items to a list box from a string array

With the help of Google and a bit of luck, I was able to write code which adds a string array to a list box and displays the duplicate total in a text box using LINQ. I now need to be able to read from the array and only display non-duplicate items in a second listbox.
Here's the code that I have so far:
private void Form1_Load(object sender, EventArgs e)
{
string[] MyStringArray = new string[20];
MyStringArray[0] = "Apple";
MyStringArray[1] = "Green";
MyStringArray[2] = "Apple";
MyStringArray[3] = "Red";
MyStringArray[4] = "Orange";
MyStringArray[5] = "Orange";
MyStringArray[6] = "Bananas";
MyStringArray[7] = "Yellow";
MyStringArray[8] = "Mango";
MyStringArray[9] = "Yellow";
MyStringArray[10] = "Cherry";
MyStringArray[11] = "Red";
MyStringArray[12] = "Fig";
MyStringArray[13] = "Brown";
MyStringArray[14] = "Fig";
MyStringArray[15] = "Brown";
MyStringArray[16] = "Fig";
MyStringArray[17] = "Orange";
MyStringArray[18] = "Brown";
MyStringArray[19] = "Cranberry";
lstbDup.Items.AddRange(MyStringArray);
List<string> dups = new List<string>();
for (int i = 0; i < MyStringArray.Length; i++)
{
string current = MyStringArray[i];
if (MyStringArray.Count(s => s == current) > 1 &&
!dups.Contains(current))
{
dups.Add(current);
}
}
txtdupdisp.Text += dups.Count.ToString();
}
Use LINQ's .Distinct() operator to remove duplicate items from a sequence:
var uniques = MyStringArray.Distinct().ToList();
foreach(string s in uniques)
yourSecondListBox.Items.Add(s);
Or simply
yourSecondListBox.Items.AddRange(MyStringArray.Distinct().ToArray());
However as stated by another answer, your question is not clear. The code above retrieves every string that appears at least one time in your array. This means that also the word 'Apple' (it appears 2 times) will be included in the second listbox.
Instead, if you want only the items that appears just one time then the answer from vc 74 is the correct one albeit a more compact version exists:
List<string> nonDuplicates = MyStringArray.GroupBy(x => x)
.Where(group => group.Count()==1)
.SelectMany(group => group).ToList();
Linq is really funny and it seems that it gives infinite ways to skin the cat.
To retrieve the non duplicates:
var groups = MyStringArray.ToLookup(str => str);
List<string> nonDuplicates = groups.Where(group => (group.Count() == 1)).
Select(group => group.Key).ToList();
you can do it like this.
List<string> list = MyStringArray.Cast<string>().Distinct().ToList();
Once you get the filtered data bind this list to your control.
listBox1.DataSource = list;

Categories

Resources