Linq just starting out - c#

I'm just trying to teach myself how to use Linq. This is what I have
if (FileReceivers.Exists(t => t.FileName == filename))
{
//I also want to do a c.Parent = proper FileReceiver
FileReceivers.Where(t=>t.FileName == filename).First().Clients.Add(c);
}
else
{
FileReceiver fr = new FileReceiver(filename);
fr.Clients.Add(c);
FileReceivers.Add(fr);
}
Any ideas how I would do this the right way? I don't really want to be using Linq to twice to grab the same thing, that would defeat the purpose.
I would just like to know the proper way to format this.

var fr = FileReceivers.FirstOrDefault(t=>t.FileName == filename);
if (fr == null) {
fr = new FileReceiver(filename);
FileReceivers.Add(fr);
}
fr.Clients.Add(c);

you could always pass the results of t => t.FileName == filename to an anonymous type and use that for later processing.

Related

Is it possible to convert this foreach loop into a LINQ-to-XML loop?

I originally asked this question (Can we automatically add a child element to an XElement in a sortable manner?) and it was closed as a duplicate (how to add XElement in specific location in XML Document).
This is teh code that I have at the moment:
bool bInserted = false;
foreach (var weekDB in xdoc.Root.Elements())
{
DateTime datWeekDB = DateTime.ParseExact(weekDB.Name.LocalName, "WyyyyMMdd", CultureInfo.InvariantCulture);
if (datWeekDB != null && datWeekDB.Date > historyWeek.Week.Date)
{
// Insert here
weekDB.AddBeforeSelf(xmlHistoryWeek);
bInserted = true;
break;
}
}
if (!bInserted)
xdoc.Root.Add(xmlHistoryWeek);
It works fine. But I wondered if I can use LINQ to acheive the same thing? The linked answer suggests:
Search element you want to add and use Add method as shown below
xDoc.Element("content")
.Elements("item")
.Where(item => item.Attribute("id").Value == "2").FirstOrDefault()
.AddAfterSelf(new XElement("item", "C", new XAttribute("id", "3")));
But I don't understand how to end up with logic like that based on my codes logic.
I think the best way to think about it is: you are going to use LINQ to find a specific element. Then you will insert into the document based on what you found.
So something like this:
var targetElement = xdoc.Root.Elements()
.Where(weekDB => {
DateTime datWeekDB = DateTime.ParseExact(weekDB.Name.LocalName, "WyyyyMMdd", CultureInfo.InvariantCulture);
return datWeekDB != null && datWeekDB.Date > historyWeek.Week.Date;
})
.FirstOrDefault();
if (targetElement == null)
{
xdoc.Root.Add(xmlHistoryWeek);
}
else
{
targetElement.AddBeforeSelf(xmlHistoryWeek);
}

How to check if a string is in an array

I am trying to check whether a string is in an array and if continues even though the fileInfo.Name.Contains a string that is in files.Any:
\\FILES LIKE DATABASE.MDB IS IN C:PROJECTS\HOLON\DATABASE.MDB
**if (files.Any((fileInfo.Name.Contains)))**
\\DO SOMETHING
Console.WriteLine(
fileInfo.Name, fileInfo.Length,
If you alread have the filenames collected in an array, then you should either do it this way:
if (files.Any() && files.Contains(fileInfo.Name))
{
// Do something
}
If you just want to check if a file exists then you can use File.Exists:
if(System.IO.File.Exists(fileInfo.Name))
{
// Do Something
}
So you have a collection of full file paths? And you want to check if one or more of those list entries match with a specific file name?
Perhaps this would work for you:
string fileToSearch = "DATABASE.MDB";
bool found = files.Any(fileName => new FileInfo(fileName).Name.ToUpper() == fileToSearch.ToUpper());
Edit:
An alternative to constructing new FileInfo objects would be to use System.IO.Path:
bool found = files.Any(fileName => Path.GetFileName(fileName).ToUpper() == fileToSearch.ToUpper());
Edit 2:
On the other hand, if you want to search for a specific file name, and you want to use the result, you could do something like this:
var fileToSearch = "DATABASE.MDB";
var fileInfo =
(from f in files
let fi = new FileInfo(f)
where fi.Name.ToUpper() == fileToSearch.ToUpper()
select fi).FirstOrDefault();
if (fileInfo != null)
{
if (fileInfo.Exists)
{
Console.WriteLine($"{fileInfo.Name} ({fileInfo.Length} bytes).");
}
else
{
Console.WriteLine($"{fileInfo.Name} (does not exist).");
}
}
I used a LINQ query here for readability. You could use the extension methods (files.Select(f => new FileInfo(f)).Where(fi => fi.Name.ToUpper() == fileToSearch.ToUpper()).FirstOrDefault()) as well, but that's up to you.
if (Array.Exists(files, element => element.Contains(fileInfo.Name)))

How to quickly cut up and reassemble a C# List?

The setup:
I have a session variable that carries a list of IDs, pipe-delimited. The IDs are related to views in my site, and related to a breadcrumb builder.
Session["breadCrumb"] = "1001|1002|1003|1004";
If I'm on the view that corresponds to 1002, I'd like to cut everything AFTER that id out of the session variable.
I'd thought to use something like:
var curView = "1002";
if (Session["breadCrumb"] != null) {
var crumb = Session["breadCrumb"].ToString().Split('|').ToList();
var viewExists = crumb.Any(c => c.Value == curView);
if (viewExists) {
//remove everything after that item in the array.
}
}
But I'm wide open to methodologies.
You could use TakeWhile to get back only the items from the splitted list that precede the currentView.
var curView = "1002";
if (Session["breadCrumb"] != null)
{
var crumb = Session["breadCrumb"].ToString().Split('|').ToList();
var viewExists = crumb.TakeWhile(c => c != curView).ToList();
viewExists.Add(curView);
string result = string.Join("|",viewExists);
}
While this approach works I think that also the previous answer (now wrongly deleted from Mr. Andrew Whitaker) was correct. Using IndexOf should be faster with less splitting, looping, joining strings. I suggest Mr Whitaker to undelete its answer.
EDIT
This is from the deleted answer from Mr.Whitaker.
I will repost here because I think that its approach is simpler and should give better perfomances, so future readers could see also this option.
var crumb = Session["breadCrumb"].ToString()
int index = crumb.IndexOf(curView);
if (index >= 0)
{
Session["breadCrumb"] = crumb.Substring(0, index + curView.Length);
}
If Andrew decide to undelete its answer I will be glad to remove this part. Just let me know.
You could just store a List<string> in the Session directly. This saves you from having to split/concat the string manually. I know this does not answer the question directly, but I believe it is a superior solution to that.
var curView = "1002";
var crumb = Session["breadCrumb"] as List<string>;
if (crumb != null) {
var viewExists = crumb.Any(c => c.Value == curView);
if (viewExists) {
// remove everything after that item in the array.
}
}
I almost regret this, but frankly I'd just go for a regular expression:
var result = Regex.Replace(input, "(?<=(\\||^)" + current + ")(?=\\||$).*", "");
This does not directly tell you if the current view existed in the input, but even though this is also possible with the regex in this particular instance another, dead simple test exists:
var viewExists = result.Length != current.Length;

if statement on a foreach

I notice i do this pattern a lot. Is there a better way to write this?
bool hit=false;
foreach (var tag in tags)
if (tag == sz)
{
hit = true;
break;
}
if (hit) continue;
//tags.add(sz); or whatever i wanted to do
I know if sz in tags exist in other languages. I hope theres something in linq that can help?
For the example:
if (tags.Contains(sz)) ...
For the more general problem:
if (tags.Any(tag => InvolvedLogic(tag))) ...
Assuming tags is a List<T>:
if (tags.Contains(sz))
{
// ...
}
If you just want to know if a given item is in tags, do:
if(tags.Any(t => t == sz))
{
// Do stuff here
}
If you want to grab a reference to the found item, do:
var foundTag = tags.FirstOrDefault(t => t == sz);
// foundTag is either the first tag matching the predicate,
// or the default value of your tag type
if (tags.Any(t=>t == sz) == true)
{
//...
}

programmatically navigate a linq to sql result

I have the following....
var jobsApplications = ( from applications in db.applications
where applications.employeeId == LogedUser.Id
select new { applications.id, applications.jobId, applications.confirmationDate });
Now I want to navigate this result like
foreach "something" in jobsApplications
But I don't now what to put in something since the select new create a new class.
Any suggestions
I guess you can let the compiler do the work for you:
foreach (var application in jobApplications)
{
// use the application wisely
}
Consider using Array.ForEach() to iterate through your IEnumerable or List. This is a bit more heavyweight.
Array.ForEach(jobsApplication, jobApp => {
if (jobApp.City == "Chicago")
{
jobApp.Approved = true;
}
});
If you want a simple foreach, then you can type the anonymous class as var
foreach (var jobApp in jobApplications)
{
if (jobApp.City == "Chicago")
{
jobApp.Approved = true;
}
}

Categories

Resources