Checking foreach loop list results C# - c#

I have this bit of code in a class:
public class TicketSummary
{
//get all the development tickets
public List<IncidentSummary> AllDevelopmentTickets { get; set; }
public List<string> TicketNames()
{
List<string> v = new List<string>();
foreach (var developmentTicket in AllDevelopmentTickets)
{
var ticketIds = developmentTicket.id.ToString(CultureInfo.InvariantCulture);
v.Add(ticketIds);
}
return v;
}
}
}
And I am trying to see if my API connection (plus all the code) did it's job and pulls back the tickets and their info, more specifically the ids.
In my main program I have no clue how to check if it did the job. I tried something but it isn't quite right and doesn't return anything ( I know I need a Console.WriteLine)
static void Main(string[] args)
{
Console.ReadLine();
var tickets = new TicketSummary();
tickets.TicketNames();
while ( tickets != null )
{
Console.WriteLine(tickets);
}
}
Any suggestions, please?
Thank you!

You've dropped the returned result: tickets.TicketNames(); returns List<String> that you have to assign and then itterate:
var tickets = new TicketSummary();
var names = tickets.TicketNames(); // <- names, List<String> according to the code
// printing out all the names
foreach(var name in names)
Console.WriteLine(name);

Do you mean you just want to print all the tickets out?
foreach (var ticket in tickets.TicketNames())
{
Console.WriteLine(ticket);
}

You have several problems in your code, that should keep it from even compiling, but aside from that, It seem's what you're really after is rather transforming the data in AllDevelopmentTickets, rather than moving it somewhere. So you could probably do it with a Select call (from LINQ). So, in your main method:
var tickets = new TicketSummary();
// add some tickets to tickets.AllDevelopmentTickets here...
var ticketNames = tickets.AllDevelopmentTickets.Select(ticket => ticket.id.ToString();
// Yes, you should probably use an UI culture in the ToString call.
// I'm just trying to limit my line width =)
Now, ticketNames should be an IEnumerable<string> holding all the ticket ids. To, for example, print them out, you can iterate over them and write to console output:
foreach (var name in ticketNames) {
Console.WriteLine(name);
}

You need to assign / use the return value of the TicketNames() method. This seems a lot of work just to return the string version of the TicketId. This can be reduced
public List<string> TicketNames()
{
return AllDevelopmentTickets
.Select(t => t.id.ToString(CultureInfo.InvariantCulture))
.ToList();
}
var ticketSummary = new TicketSummary();
var ticketNames = ticketSummary.TicketNames();
foreach(var ticketName in ticketNames)
{
Console.WriteLine(ticketName);
}
or Even just:
foreach(var ticketName in AllDevelopmentTickets
.Select(t => t.id.ToString(CultureInfo.InvariantCulture)))
{
Console.WriteLine(ticketName);
}

You're ignoring the returned value.
static void Main(string[] args)
{
Console.ReadLine();
var tickets = new TicketSummary();
var res = tickets.TicketNames();
while ( for r in res )
{
Console.WriteLine(r);
}
}

Related

How to prevent a duplicate item from being generated in a Foreach loop in C#

I have a foreach loop which builds search results and sometimes it would return the same Page Name and Description, but the link would be different as it has a 3rd party Gallery Module which has different queries in the URL.
For example:
Resources/Videos/emodule/936/eitem/75 would have one video
and
/Resources/Videos/emodule/936/eitem/73 would be different.
The Title and Description is the same.
How would I change my foreach loop to check if the Page Title is the same and if it is the same, exclude the sb.AppendLine search result?
This is my current code:
TotalPageResults = "0";
var searchResults = SearchController.Instance.ModuleSearch(query);
if(searchResults != null)
{
TotalPageResults = searchResults.TotalHits.ToString();
var sb = new StringBuilder();
sb.AppendLine("<div class='page_results'><span class='page_results_text'>Page Results:</span></br>");
foreach(var result in searchResults.Results)
{
sb.AppendLine($"</br><span><a href='{result.Url}' class='page_results_link'>{result.Title}</a></span></br><span class='page_result_description'>{result.Description}</span></br><span class='page_results_date_modified'>Updated: {result.DisplayModifiedTime}</span></br>");
}
sb.AppendLine("</div>");
DNNSearchResuls = sb.ToString();
}
Keep a set of results you've already seen, and check if it's new before 'doing the thing'
var stuffImThinkinAbout = new List<string>();
var stuffIAlreadyHave = new HashSet<string>();
foreach (var i in stuffImThinkinAbout)
{
if (!stuffIAlreadyHave.Contains(i))
{
//do the thing
stuffIAlreadyHave.Add(i);
}
else
{
//skip dupe
}
}
Then use title or whatever as your 'key' to make them unique.
Would could check if the Stringbuilder already contains the title and description. Somthing along the lines:
foreach(var result in searchResults.Results)
{
if(!sb.ToString().Contains(result.Title) && !sb.ToString().Contains(result.Description)
sb.AppendLine($"</br><span><a href='{result.Url}' class='page_results_link'>{result.Title}</a></span></br><span class='page_result_description'>{result.Description}</span></br><span class='page_results_date_modified'>Updated: {result.DisplayModifiedTime}</span></br>");
}
}
Try using GroupBy on the property you want to distinct and select only one record in the group.
This code for only property Title
foreach (var result in searchResults.Results.GroupBy(p => p.Title).Select(g => g.First())
{
}
or 2 properties Title and Description
foreach (var result in searchResults.Results.GroupBy(p => new {p.Title, p.Description}).Select(g => g.First())
{
}

very slow C#/linq loop need improvement suggestions

I have the following piece of code that I use to try to see if copying data from one table to an other missed some records.
There are reasons why this can happen but I won't go into the details here.
Now fortunately, this code runs against a few hundred records at a time, so I can allow myself lo load them into memory and use LINQ to Objects.
As I expected, my code is very slow and I'm wondering if anyone could suggest any way to improve the speed.
void Main()
{
var crossed_data = from kv in key_and_value_table
from ckv in copy_of_key_and_value_table
where kv.key != ckv.key
select new { KeyTable = kv, copyKeyTable = ckv };
List<Key_and_value> difference = new List<Key_and_value>();
foreach (var v in crossed_data)
{
if (crossed_data.Select(s => s.Kv.key).ToList().
Contains(v.ckv.Key) == false)
{
difference.Add(v.ckv);
}
}
}
public class Key_and_value
{
public string Key { get; set; }
public decimal Value { get; set; }
}
many thanks in advance
B
You are doing your Select every iteration when you do not need to. You can move it to the external scope like so.
var keys = crossed_data.Select(s=>s.ckv.key).ToList();
foreach(var v in crossed_data )
{
if (keys.Contains(v.kv.Key) == false)
{
difference.Add(v.Kv);
}
}
This should improve the speed a fair bit.

Edit Web Config file and apply changes

Am doing a windows application in c#, where i read web.config files inside a folder and load the appsettings where users can edit them and apply changes.
I store the settings 'key' and 'value' in a dictionary and the effected values in a separate dictionary . It works well, but it takes lot of time to apply the changes.
How can i speed it up?
here is my code
public List<AppSettings> OldAppSetting;
public List<AppSettings> NewAppSetting;
foreach (var oldSetList in OldAppSetting)
{
Document = Document = XDocument.Load(#oldSetList.FilePathProp);
var appSetting = Document.Descendants("add").Select(add => new
{
Key = add.Attribute("key"),
Value = add.Attribute("value")
}).ToArray();
foreach (var oldSet in appSetting)
{
foreach (var newSet in NewAppSetting)
{
if (oldSet.Key != null)
{
if (oldSet.Key.Value == newSet.AppKey)
{
oldSet.Value.Value = newSet.AppValue;
}
}
Document.Save(#oldSetList.FilePathProp);
}
}
}
here is the Appsettings class
public class AppSettings
{
public string AppKey { get; set; }
public string AppValue { get; set; }
public string FilePathProp{ get; set; }
}
I think your primary speed concern is that you're saving the document after checking every item. Seems like you could change your code to reduce the number of times you call save. For example:
foreach (var oldSetList in OldAppSetting)
{
Document = Document = XDocument.Load(#oldSetList.FilePathProp);
var appSetting = Document.Descendants("add").Select(add => new
{
Key = add.Attribute("key"),
Value = add.Attribute("value")
}).ToArray();
foreach (var oldSet in appSetting)
{
foreach (var newSet in NewAppSetting)
{
if (oldSet.Key != null)
{
if (oldSet.Key.Value == newSet.AppKey)
{
oldSet.Value.Value = newSet.AppValue;
}
}
}
}
Document.Save(#oldSetList.FilePathProp);
}
Also, you could use a Dictionary<string, AppSetting> rather than an array for your appSetting. That would speed things up quite a bit if the number of items is large. It would take some restructuring of your code. I don't know what all of your types are, so I can't give you the exact code, but it would look something like this:
var appSetting = Document.Descendants("add")
.ToDictionary(add => add.Attribute("key"));
foreach (var newSet in NewAppSetting)
{
if (appSetting.ContainsKey(newSet.AppKey))
{
var oldSet = appSetting[newSet.AppKey];
oldSet.Value.Value = newSet.AppValue;
}
}
Your code is a little bit confusing, but I think that's right. The idea here is to build a dictionary of the old values so that we can look them up directly when scanning the new values. It turns your O(n^2) algorithm into an O(n) algorithm, which will make a difference if there are a lot of settings. Plus, the code is smaller and easier to follow.
Put the
Document.Save(#oldSetList.FilePathProp);
Outside the loop!

Enumerated int List<GradeRange>

I really have no clue about enumerated list, but after some research I found that this list may help solve my problem. So I have a string in my settings called strGrades, and it is a range of strings that I manually update. The range is 0155-0160, 0271-0388, 0455-0503, 0588-687. What I basically want to do is find the values that are not in this grade list (for example 0161,0389, 0504-0587...)
So I came up with a function that will allow me to get each match in the grade range:
public static List<GradeRange> GetValidGrades()
{
MatchCollection matches= Regex.Matches(Settings.Default.productRange,
Settings.Default.srGradeRange);
List<GradeRange> ranges= new List<GradeRange();
if(matches.Count >0)
{
foreach (Match match in matches)
{
ranges.Add(new GradeRange() 23 {
Start= int.Parse(match.Groups["Start"].Value),
Stop= int.Parse(match.Groups["Stop"].Value)
});
}
}
return ranges;
}
here is the grade range class
public class GrandRange
{
public int Start{get; set;)
public int Stop {get; set; )
}
So the function above caputures my Start and End values, can anyone please help me get this into a list where I can find the values that fall outside of the range values, I just need a starting point. Thanks so much!
You could use a custom extension method that creates .Between along with a Where
var myFilteredList = list.Where(x=>!myValue.Between(x.Start, x.Stop, true));
This isnt the most performant answer, but if you need a list of all the numbers that are not between certain ranges, then you could do something like this:
var missingNumbers = new List<int>();
var minStop = list.OrderBy(x=>x.Stop).Min().Stop;
var maxStart = list.OrderBy(x=>x.Start).Max().Start;
Enumerable.Range(minStop, maxStart).ToList()
.ForEach(x=>
{
if(!x.Between(x.Start, x.Stop, true))
missingNumbers.Add(x);
}
);
Here this should get you started
var strings = "0155-0160, 0271-0388, 0455-0503, 0588-687";
var splitStrings = strings.Split(char.Parse(","));
var grads = new List<GrandRange>();
foreach (var item in splitStrings) {
var splitAgain = item.Split(char.Parse("-"));
var grand = new GrandRange
{
Start = int.Parse(splitAgain[0]),
Stop = int.Parse(splitAgain[1])
};
grads.Add(grand);
}
}

C# foreach only get distinct values

I have the following code:
foreach (Logs log in _logsDutyStatusChange)
{
string driverid = log.did;
}
How would I only add distinct driver ID's to the driverid string?
Thanks
You should do:
foreach (string id in _logsDutyStatusChange.Select(x=>x.did).Distinct())
{
string driverid = id;
}
mhh ... maybe use IEnumerable< T >'s Distinct() function?
Your code isn't adding anything right now, it's just setting a string (declared in the scope of the loop) to each value. The end result would be only the last value, and it would be out of scope to the following code anyway. If you're trying to append them all to a string, separated by commas, e.g., try this:
string driverids = string.Join(",", _logsDutyStatusChange
.Select(item=>item.did)
.Distinct()
.ToArray());
This should work (without linq):
Hashset<string> alreadyEncountered = new Hashset<string>();
foreach (Logs log in _logsDutyStatusChange)
{
if(alreadyEncountered.Contains(log.did))
{
continue;
}
string driverid = log.did;
alreadyEncountered.Add(driverid);
}
First, create a comparer class and implement the IEqualityComparer<Log> interface:
public class LogComparer : IEqualityComparer<Log>
{
public bool Equals(Log one, Log two)
{
return one.did.Equals(two.did);
}
public int GetHashCode(Log log)
{
return log.did.GetHashCode();
}
}
And then use the overload of the Enumerable.Distinct() method that takes an instance of the equality comparer:
foreach(var log in _logsDutyStatusChange.Distinct(new LogComparer()))
{
// Work with each distinct log here
}
Instead of foreach'ing _logsDutyStatusChange, you could use LINQ to get a collection of distinct and loop through those, instead:
foreach (Logs log in _logsDutyStatusChange.Select(l => l.did).Distinct())
{
//Handling code here
}
Implementation will depend exactly on what you intend to do with the results.
You can use Distinct if your Logs class implements IEquatable
Otherwise, a quick 'hacky' fix can be to use something like
foreach (var group in _logsDutyStatusChange.GroupBy(l => new { log.did, .... more identifying fields })
{
string driverid = group.Key.did;
}
C# 4.0 tuples have 'automagic' comparing/equating as well
Here's one approach:
HashSet<string> SeenIDs = new HashSet<string>();
foreach (Logs log in _logsDutyStatusChange)
{
if (SeenIDs.Contains(log.did)) break;
SeenIDs.Add(log.did);
string driverid = log.did;
}
Distinct() doesn't quite work here, as it will only get you the distinct dids.

Categories