Assist with simple count out of a list - c#

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

Related

Nested foreach loops with side effects for Entity Framework

I have problem with nested foreach loops because of following example:
var someList = new List<SimpleC>();
simpleA = database.SimpleA.ToList();
simpleB = database.SimpleB.ToList();
foreach (var a in simpleA)
{
foreach (var b in simpleB)
{
var c = new simpleC();
c.simpleAId = a.Id;
c.simpleAName = a.Name;
c.simpleBName = b.Name;
someList.Add(c);
}
}
return someList;
The problem: imagine first iteration it goes to first foreach loop then to second foreach loop it initiates new object, maps values and adds newly initiated object to new list, but when second iteration comes instead of going back to first foreach loop it continues with second foreach loop and it loops through second until it finishes, I understand that's how C# works, but I need side effect for it to continue to first foreach loop to get new values.
You would be much better served by not trying to iterate this manually, establishing a relationship and querying it as a join set of entities:
var results = database.SimpleA
.Join(database.SimpleB,
a => a.ID,
b => b.Post_ID, /
(a, b) => new { colA = a, colB = b })
.Select new SimpleA(){
Property1 = a.Col1,
Property2 = b.Col3,
Property4 = a.Col2
}).ToList();
This is only mostly functional as a starting point. You might need a left outer join instead.
Another option, if A and B have a fk constraint in the database, then you may use Navigation properties instead of a join.
If for whatever reason, your loop is required we can try and breakdown the issue:
foreach (var a in simpleA)
{
foreach (var b in simpleB) // There is no relationship here!
{
var c = new simpleC();
c.simpleAId = a.Id;
c.simpleAName = a.Name;
c.simpleBName = b.Name;
someList.Add(c);
}
}
You could try using the index, but that is very likely to cause issues.
Instead:
foreach (var a in simpleA)
{
var matchedB = simpleB.Where(x => x.Id == a.Id).FirstOrDefault();
var c = new simpleC();
c.simpleAId = a.Id;
c.simpleAName = a.Name;
c.simpleBName = matchedB.Name;
someList.Add(c);
}
I think, if I'm understanding your question, is that you don't want it to loop through in a nested fashion, but only loop once. To do that you'd do it like this.
for(int i = 0; i < simpleA.Count; i++)
{
var c = new simpleC();
c.simpleAId = simpleA[i].Name;
c.simpleAName = simpleA[i].Name;
c.simpleBName = simpleB[i].Name;
someList.Add(c);
}

C# How to make a list out of IEnumerable

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);

Iterate through 2 lists of shapes within a single foreach C#

I have 2 lists of shapeIds from 2 seperate PowerPoint presentations, one from and original PowerPoint and another from an edited PowerPoint.
I now want to compare the items in these 2 lists ShapeId's to each other. For example I want to compare the colour and the font size etc.
I've tried a number of ways to do this and decided the best way to would be to iterate through each ShapeId in the 2 lists. Is there anyway I can iterate through each list within one foreach loop? Such as foreach (Microsoft.Office.Interop.PowerPoint.Slide slide item1 in list1, Microsoft.Office.Interop.PowerPoint.Slide slide item2 in list2)
My code is as fallows
Microsoft.Office.Interop.PowerPoint.CustomLayout customLayout = pptPresentationOriginal.SlideMaster.CustomLayouts[Microsoft.Office.Interop.PowerPoint.PpSlideLayout.ppLayoutText];
Microsoft.Office.Interop.PowerPoint.Slides Originalslides;
Microsoft.Office.Interop.PowerPoint.Slides EditedSlides;
Microsoft.Office.Interop.PowerPoint.Shape originalShp;
Microsoft.Office.Interop.PowerPoint.Shape editShp;
Originalslides = pptPresentationOriginal.Slides;
EditedSlides = pptPresentationEdit.Slides;
List<char> l = new List<char>();
List<char> l2 = new List<char>();
List<int> originalShapesListID = new List<int>();
List<int> editedShapesListID = new List<int>();
List<int> originalListID = new List<int>();
List<int> editedListID = new List<int>();
List<Microsoft.Office.Interop.PowerPoint.Shape> originalList = new List<Microsoft.Office.Interop.PowerPoint.Shape>();
List<Microsoft.Office.Interop.PowerPoint.Shape> editList = new List<Microsoft.Office.Interop.PowerPoint.Shape>();
Microsoft.Office.Interop.PowerPoint.Shape editedShpID;
Logic
String pps = "";
foreach (Microsoft.Office.Interop.PowerPoint.Slide slide in Originalslides)
{
foreach (Microsoft.Office.Interop.PowerPoint.Shape originalShape in slide.Shapes)
{
originalShp = originalShape;
if (originalShape.HasTextFrame == Microsoft.Office.Core.MsoTriState.msoTrue)
{
var textFrame = originalShape.TextFrame;
if (textFrame.HasText == Microsoft.Office.Core.MsoTriState.msoTrue)
{
var textRange = textFrame.TextRange;
pps += originalShape.TextFrame.TextRange.Text;
foreach (char word in pps)
{
l.Add(word);
Debug.WriteLine(word);
}
}
}
originalShapesListID.Add(originalShape.Id);
originalShapeID = originalShape.Id;
originalList.Add(originalShape);
}
originalListID.Add(slide.SlideID);
}
foreach (Microsoft.Office.Interop.PowerPoint.Slide slide in EditedSlides)
{
foreach (Microsoft.Office.Interop.PowerPoint.Shape editShape in slide.Shapes)
{
editShp = editShape;
if (editShape.HasTextFrame == Microsoft.Office.Core.MsoTriState.msoTrue)
{
var textFrame = editShape.TextFrame;
if (textFrame.HasText == Microsoft.Office.Core.MsoTriState.msoTrue)
{
var textRange = textFrame.TextRange;
pps += editShape.TextFrame.TextRange.Text;
foreach (char word in pps)
{
l.Add(word);
Debug.WriteLine(word);
}
}
}
editedShapesListID.Add(editShape.Id);
editedShapeID = editShape.Id;
editList.Add(editShape);
}
editedListID.Add(slide.SlideID);
}
Here is where I want to go through the 2 lists and compare each item (ShapeId) in each list. I want to do something like this.
foreach (Microsoft.Office.Interop.PowerPoint.Shape editShape in editedShapesListID, Microsoft.Office.Interop.PowerPoint.Shape original in originalShapesListID )
{
if (originalShapeID == editedShapeID)
{
if (original.TextFrame.TextRange.Font.Color.RGB != editShape.TextFrame.TextRange.Font.Color.RGB)
{
originalShp.TextFrame2.TextRange.Font.StrikeThrough.ToString();
}
}
}
Since you want to match the items on a specific key Id. A good option would be to use a join. Join will build a hash-table for the inner collection which has O(1) lookup.
var q = from original in originalShapes
join editedTmp in editedShapes on original.Id equals editedTmp.Id into g
from edited in g.DefaultIfEmpty()
select new
{
original,
edited
};
foreach(var item in q)
{
//item.edited might be null if no matching original was found.
if (item.edited == null || item.original.TextFrame.TextRange.Font.Color.RGB != item.edited.TextFrame.TextRange.Font.Color.RGB)
{
item.original.TextFrame2.TextRange.Font.StrikeThrough.ToString();
}
}
using (var originalEnumerator = originalShapesListID.GetEnumerator())
foreach (var editShape in editedShapesListID)
{
if (!originalEnumerator.MoveNext()) break;
var original = originalEnumerator.Current;
...
}
You can use 2 Dictionary instead of 4 Lists and then using Join.
Here is an example with int and string (replace string with Microsoft.Office.Interop.PowerPoint.Shape for your issue):
Dictionary<int, string> loDicOriginal = new Dictionary<int, string>();
Dictionary<int, string> loDicEdit = new Dictionary<int, string>();
loDicOriginal.Add(1, "int 1 list 1");
loDicOriginal.Add(2, "int 2 list 1");
loDicOriginal.Add(3, "int 3 list 1");
loDicEdit.Add(1, "int 1 list 2");
loDicEdit.Add(3, "int 3 list 2");
var loQuery = loDicOriginal.Join(loDicEdit,
dicOrg => dicOrg.Key,
dicEdit => dicEdit.Key,
(entryOrg, entryEdit) => new { Original = entryOrg, Edit = entryEdit });
foreach (var loOut in loQuery)
{
System.Diagnostics.Debug.WriteLine("{0}->{1} | {2}->{3}", loOut.Original.Key, loOut.Original.Value, loOut.Edit.Key, loOut.Edit.Value);
}
Output is:
1->int 1 list 1 | 1->int 1 list 2
3->int 3 list 1 | 3->int 3 list 2
I hope it is clear what I mean.

How to add calculated fields to SQL list

I am tracking fuel for trucks.
List<FuelLightTruckDataSource> data = new List<FuelLightTruckDataSource>();
using (SystemContext ctx = new SystemContext())
{
List<FuelLightTruckDataSource> dataTransfers
= ctx.FuelTransfer
.Where(tr => DbFunctions.TruncateTime(tr.Date) >= from.Date && DbFunctions.TruncateTime(tr.Date) <= to.Date
//&& tr.ToAsset.AssignedToEmployee.Manager
&& tr.ToAsset.AssignedToEmployee != null
&& tr.ToAsset.AssetType.Code == "L"
&& tr.Volume != null)
//&& (tr.FuelProductType.FuelProductClass.Code == "GAS" || tr.FuelProductType.FuelProductClass.Code == "DSL"))
.GroupBy(tr => new { tr.ToAsset, tr.Date, tr.FuelTankLog.FuelProductType.FuelProductClass, tr.FuelTankLog.FuelCard.FuelVendor,tr.Volume, tr.ToAssetOdometer })
.Select(g => new FuelLightTruckDataSource()
{
Asset = g.FirstOrDefault().ToAsset,
Employee = g.FirstOrDefault().ToAsset.AssignedToEmployee,
ProductClass = g.FirstOrDefault().FuelTankLog.FuelProductType.FuelProductClass,
Vendor = g.FirstOrDefault().FuelTankLog.FuelCard.FuelVendor,
FillSource = FuelFillSource.Transfer,
Source = "Slip Tank",
City = "",
Volume = g.FirstOrDefault().Volume.Value,
Distance = g.FirstOrDefault().ToAssetOdometer,
Date = g.FirstOrDefault().Date,
})
.ToList();
After my query, I need to calculate the consumption rate and distance traveled. "Result" will be a collection of entries including "consumptionRate" and "Distance" and it matches the query above.
// Get consumption rate data for each asset
foreach (int assetId in assetIds)
{
FuelConsumptionRateQueryResult result = FuelConsumptionRateQueryService.Get(assetId, from, to, AssetCounterType.Odometer);
result.Entries.ToList();
}
My question is how do I get the result of my foreach loop and add them to my previous query/list, so they can show up in the report?
Your issue seems to be due to the fact that you're declaring result as a new variable at each iteration of the foreach loop, causing result to be overwritten. Additionally, result isn't in scope once you finish with the foreach loop.
Instead, you probably want something closer to:
var allResults = new List<T>; //where T is whatever object type this is (FuelConsumptionRateQueryResult?)
foreach (int assetId in assetIds)
{
//this is a new variable at each iteration of the loop
FuelConsumptionRateQueryResult result = FuelConsumptionRateQueryService.Get(assetId, from, to, AssetCounterType.Odometer);
allResults.Add(result); //add the current result to your list (outside the scope of this loop)
}
Basically, declare your variable outside of the loop and Add each individual result to the allResults list.
Create the additional data by a LINQ statement and concatenate both lists:
var results = assetIds.Select(id => FuelConsumptionRateQueryService
.Get(id, from, to, AssetCounterType.Odometer);
dataTransfers = dataTransfers.Concat(results);

dictionary of lists in c#(cant seem to get my lists)

Here i used linq to filter my result in an array and pass into a list and from that list into a dictionary as you can see below
//array is a multidimensional array with string data in it
var datumn = array;
var list = new List<string>();
var stringcounts = new Dictionary<int,List<string>>();
var listtemp = new List<string>();
//linq
var arrayresult = from string a in datumn where a != "FREE" select a;
//adding result from arrayresult to list
foreach (var listing in arrayresult)
{
list.Add(listing);
}
//using linq again i filter my list then add to dictionary
for (int count = 3; count > 0; count-- )
{
var duplicateItems = from x in list
group x by x into grouped
where grouped.Count() == count
select grouped.Key;
foreach (var replace in duplicateItems)
{
listtemp.Add(replace.ToString());
}
stringcounts.Add(count, lists);
//clearing the list to avoid duplicating data in my dictionary
listtemp.Clear();
}
for (int key = stringcounts.Count; key > 0; --key)
{
var holding = stringcounts[key];
foreach (var li in holding)
{
MessageBox.Show(li.ToString());
//just view what i have to check if the data is correct
}
}
`
the program skips iterator over of the lists and ends can some one help with this
and i have tried everything including linq and other collections like hashtable
and maps but nothing works and it is not a console application
This line is wrong:
var dict = new Dictionary<int, List<string>>();
Remove the ";".
Result:
indigo silver violet purple green pink red brown yellow
Edit: full code for comparison:
var dict = new Dictionary<int, List<string>>()
{
{1, new List<string>{"red", "brown", "yellow"}},
{2, new List<string>{"purple", "green", "pink"}},
{3, new List<string>{"indigo", "silver", "violet"}}
};
// now i want to get my values from the lists in the dictionary
for (int count = 3; count > 0; count--)
{
var l = dict[count];
foreach (var li in l)
{
li.Dump();
}
}
foreach (var item in dict)
{
var list = item.Value;
foreach (var str in list)
{
MessageBox.Show(str);
}
}
The listtemp.Clear() is a bad syntax so therefore it should be removed and the listtemp should be declared in the for loop therefore removing redundancy and the initial problem

Categories

Resources