var filePaths = Directory.GetFiles(#"\\Pontos\completed\", "*_*.csv").Select(p => new { Path = p, Date = System.IO.File.GetLastWriteTime(p) })
.OrderBy(x => x.Date)
.Where(x => x.Date >= LastCreatedDate);
i would like to know the value of the most recent x.Date
from this linq statement how can i get the most recent date?
please note that i do not need the filepath rather i need the DATE
var mostRecent = Directory.GetFiles(#"\\Pontos\completed\", "*_*.csv")
.Select(p => new { Path = p, Date = System.IO.File.GetLastWriteTime(p) })
.OrderBy(x => x.Date)
.Where(x => x.Date >= LastCreatedDate)
.LastOrDefault();
or
var mostRecent = Directory.GetFiles(#"\\Pontos\completed\", "*_*.csv")
.Select(p => new { Path = p, Date = System.IO.File.GetLastWriteTime(p) })
.OrderByDescending(x => x.Date)
.Where(x => x.Date >= LastCreatedDate)
.FirstOrDefault();
Just reverse the order - also do the filtering before the ordering:
var filePaths = Directory.GetFiles(#"\\Pontos\completed\", "*_*.csv").Select(p => new { Path = p, Date = System.IO.File.GetLastWriteTime(p) })
.Where(x => x.Date >= LastCreatedDate)
.OrderByDescending(x => x.Date)
.FirstOrDefault();
Instead I would suggest you use DirectoryInfo's GetFiles() instead which returns FileInfo instances so you don't have to grab the last write time manually:
var di = new DirectoryInfo(#"\\Pontos\completed\");
var file = di.GetFiles("*_*.csv")
.Where(f=> f.LastWriteTimeUtc >= LastCreatedDate)
.OrderByDescending(f => f.LastWriteTimeUtc)
.FirstOrDefault();
if(file!=null)
{
Console.WriteLine("Path: {0}, Last Write Time: {1}", file.FullName,
file.LastWriteTimeUtc);
}
F# has a handy MaxBy() function that I like to use; the C# implementation is trivial. It allows you to avoid the cost of sorting the sequence.
See this answer for more detail: https://stackoverflow.com/a/8759648/385844
usage:
var mostRecent = Directory.GetFiles(#"\\Pontos\completed\", "*_*.csv")
.Select(p => new { Path = p, Date = System.IO.File.GetLastWriteTime(p) })
.Where(x => x.Date >= LastCreatedDate)
.MaxBy(x => x.Date);
you can use the method .Take(1);
Try this:
var filePaths = Directory.GetFiles(#"\\Pontos\completed\", "*_*.csv")
.Select(p => new { Path = p, Date = System.IO.File.GetLastWriteTime(p) })
.OrderByDescending(x => x.Date)
.Where(x => x.Date >= LastCreatedDate)
.FirstOrDefault();
The changes to your statement are the sorting (OrderByDescending instead of OrderBy) to put the newest date "on top" and FirstOrDefault which will select the top, single item from the collection and should result in null if the collection is empty.
To get more file properties you could modify your anonymous object to include more properties, thusly:
var filePath = Directory.GetFiles(#"\\Pontos\completed\", "*_*.csv")
.Select(p => new { Path = p, Date = File.GetLastWriteTime(p), CreatedDate = File.GetCreationTime(p) })
.OrderByDescending(x => x.Date)
.Where(x => x.Date >= DateTime.Now)
.FirstOrDefault();
Console.WriteLine(filePath.Date);
Console.WriteLine(filePath.Path);
Console.WriteLine(filePath.CreatedDate);
Or more succinctly (no need for an anonymous object) you could do this:
var filePath = new DirectoryInfo(#"\\Pontos\completed\").GetFiles("*_*.csv")
.Select(p => p)
.OrderByDescending(p => p.CreationTime)
.Where(x => x.CreationTime >= DateTime.Now)
.FirstOrDefault();
Console.WriteLine(filePath.CreationTime);
Console.WriteLine(filePath.FullName);
As you're using LinqToObjects, if performance is a consideration, you should perhaps consider implementing a MaxBy type method, instead of using OrderBy combined with FirstOrDefault.
I'll find you an implementation. [no need... see #phoog's answer]
Related
I want to translate this into lambda syntax and can't seem to get it to work:
Grouping by two columns, select max on a different column, return list of complete complex object.
I am writing more text here to get past the validation on this form. How much text is needed until I am allowed to post this?
_clientpolicies = (from policy in
_reply.CommercialInsuredGroupWithPolicyTerm.InsuredWithPolicyTerm.SelectMany(x => x.PolicyTerm)
.Where(x => !(string.IsNullOrWhiteSpace(x.PolicyNumber) && string.IsNullOrWhiteSpace(x.ControlNumber)))
.Where(x => x.Insured.DNBAccountNumber == _client.LookupID)
group policy by
new
{
PolicyReference = GetPolicyReference(policy),
PolicyType = policy.ProductInformation.PolicyTypeCode
}
into g
let maxPolicyInception = g.Max(p => p.InceptionDate)
from policyGroup in g
where policyGroup.InceptionDate == maxPolicyInception
select policyGroup).ToList();
I dont think there's a way of doing it in one line. So there's my try :
policyGroups=
_reply.CommercialInsuredGroupWithPolicyTerm.InsuredWithPolicyTerm
.SelectMany(x => x.PolicyTerm)
.Where(x => !(string.IsNullOrWhiteSpace(x.PolicyNumber) && string.IsNullOrWhiteSpace(x.ControlNumber)))
.Where(x => x.Insured.DNBAccountNumber == _client.LookupID)
.GroupBy(x => GetPolicyReference(x))
.ThenBy(x => x.ProductInformation.PolicyTypeCode)
.ToList();
var maxPolicyInception = policyGroups.Max(p => p.InceptionDate);
_clientpolicies = policyGroups
.Where(g => g.InceptionDate == maxPolicyInception)
.ToList();
_clientpolicies =
_reply.CommercialInsuredGroupWithPolicyTerm.InsuredWithPolicyTerm.SelectMany(x => x.PolicyTerm)
.Where(x => !(string.IsNullOrWhiteSpace(x.PolicyNumber) && string.IsNullOrWhiteSpace(x.ControlNumber)))
.Where(x => x.Insured.DNBAccountNumber == _client.LookupID)
.GroupBy(x =>
new
{
PolicyReference = GetPolicyReference(x),
PolicyType = x.ProductInformation.PolicyTypeCode
},
(key, g) => g.OrderByDescending(gx => gx.InceptionDate).First()
Trying to get my head around Linq, and at the same time keep track of the time I log on in the morning, which should be the time I get into the office thereabouts.
My code so far is:
EventLog SecurityLog = new EventLog("Security");
var AccountLoggedOnEntries = SecurityLog.Entries.Cast<EventLogEntry>()
.Where(x => x.InstanceId == 4624)
.Select(x => new
{
DateGenerated = x.TimeGenerated.ToShortDateString()
,
TimeGenerated = x.TimeGenerated.ToShortTimeString()
,
x.Message
})
.ToList();
DgvLogSummary.DataSource = AccountLoggedOnEntries;
DgvLogSummary.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.DisplayedCells;
I want to filter the results so that I only have one entry for each day, which is the earliest time.
In SQL I would normally take the Message of the earliest entry and then group by all fields.
How do I perform a similar query in Linq?
In LINQ you would group by, sort each group, and pick the first item:
var AccountLoggedOnEntries = log.Entries.Cast<EventLogEntry>()
.Where(x => x.InstanceId == 4624)
.GroupBy(x => x.TimeGenerated.Date)
.Select(g => g.OrderBy(x => x.TimeGenerated).First())
.Select(x => new {
DateGenerated = x.TimeGenerated.ToShortDateString()
, TimeGenerated = x.TimeGenerated.ToShortTimeString()
, x.Message
})
.ToList();
You could GroupBy the date and then select the minimum time
var AccountLoggedOnEntries = log.Entries.Cast<EventLogEntry>()
.Where(x => x.InstanceId == 4624)
.GroupBy(x => x.TimeGenerated.Date)
.Select(x => new {
DateGenerated = x.Key
, TimeGenerated = x.Min(y => y.TimeGenerated).ToShortTimeString()
})
.ToList();
Getting the appropriate Message is a little more tricky. One easy option is to use x.First().Message in the above Select projection.
Try this :
var AccountLoggedOnEntries = log.Entries.Cast<EventLogEntry>()
.Where(x => x.InstanceId == 4624)
.GroupBy(x => x.TimeGenerated.Date)
.Select(days => days.OrderBy(time => time.TimeGenerated).FirstOrDefault())
.Select(x => new
{
DateGenerated = x.TimeGenerated.ToShortDateString()
,
TimeGenerated = x.TimeGenerated.ToShortTimeString()
,
x.Message
})
.ToList();
I have a fairly complicated query that would read from a table, then do group on CONTACT_ID, then select only those group with count of 1.
This query is fairly complicated and I have no idea how to optimize it in LINQ.
var linkTable = this.DB.Links
.Where(l=>l.INSTANCE_ID==123456 && l.CONTACT_ID.HasValue && l.ORGANISATION_ID.HasValue)
.Select(l => new { l.DEFAULT_LINKED_ORGANISATION, l.LINK_ID, l.CONTACT_ID });
var defaultOrganizationLinkQuery = linkTable
.Where(l => l.DEFAULT_LINKED_ORGANISATION)
.Select(l => l.LINK_ID);
var singleOrganizationLinkQuery = linkTable
.GroupBy(l => l.CONTACT_ID)
.Select(group => new
{
CONTACT_ID = group.Key,
contact_link_count = group.Count(),
LINK_ID = group.First().LINK_ID
})
.Where(l => l.contact_link_count == 1)
.Select(l => l.LINK_ID);
var merged = singleOrganizationLinkQuery.Union(defaultOrganizationLinkQuery);
I made shorter version, but I do not expect it to be faster. If it works and is not slower I would be satisfied:
var merged = this.DB.Links
.Where(l=>l.INSTANCE_ID==123456 && l.CONTACT_ID.HasValue && l.ORGANISATION_ID.HasValue)
.GroupBy(l => l.CONTACT_ID)
.SelectMany(s => s.Where(x => s.Count() == 1 || x.DEFAULT_LINKED_ORGANISATION)
.Select(link => link.LINK_ID));
This works fine.g.Key is not null and has appropriate data:
var result = db.JournalEntries.Include(je => je.JournalRecords.Select(jr => jr.Account).Select(j => j.AccountParticulars))
.Where(je => je.Date >= existingLedgerTransaction.From && je.Date <= existingLedgerTransaction.To)
.SelectMany(s => s.JournalRecords)
.GroupBy(d => d.AccountParticular.Account.AccountCategory)
.Select(g => new { Name = g.Key.Name });
But this does not work as g.Key is null:
var DateFilter = new Func<JournalEntry, bool>(je => je.Date >= existingLedgerTransaction.From && je.Date <= existingLedgerTransaction.To);
var result = db.JournalEntries.Include(je => je.JournalRecords.Select(jr => jr.Account).Select(j => j.AccountParticulars))
.Where(DateFilter)
.SelectMany(s => s.JournalRecords)
.GroupBy(d => d.AccountParticular.Account.AccountCategory)
.Select(g => new { Name = g.Key.Name });
I tried the same thing in a simple console app with static collection and passing in predicate works fine. What could be the problem here?
NOTE: Lazy loading/dynamic proxy is disabled
Try
var DateFilter = new Expression<Func<JournalEntry, bool>>(je => je.Date >= existingLedgerTransaction.From && je.Date <= existingLedgerTransaction.To);
as you need to pass an expression tree to EF
I need to get list of files sorted by name from directory.
My files are named as:
TestFile_1.xml,
TestFile_2.xml
TestFile_3.xml
.
.
TestFile_10.xml
TestFile_11.xml
I am using below snippet for sorting
DirectoryInfo di = new DirectoryInfo(jsonFileInfo.FolderPath);
FileSystemInfo[] files = di.GetFileSystemInfos();
var orderedFiles = files.OrderBy(f => f.Name);`
with this snnipet, I am getting result as
TestFile_1.xml,
TestFile_10.xml
TestFile_11.xml
.
.
TestFile_2.xml
TestFile_3.xml
.
.
How do I sort it?
A name is a string and a "10" is not larger than "2". If you want to sort by the number after the underscore:
var orderedFiles = files
.Select(f => new{
File = f,
NumberPart = f.Name.Substring(f.Name.IndexOf("_") + 1)
})
.Where(x => x.NumberPart.All(Char.IsDigit))
.Select(x => new { x.File, Number = int.Parse(x.NumberPart) })
.OrderBy(x => x.Number)
.Select(x => x.File);
If you want to include all files which don't end with the number anyway, those should come first:
orderedFiles = files
.Select(f => new
{
File = f,
NumberPart = f.Name.Substring(f.Name.IndexOf("_") + 1)
})
.Select(x => new { x.File, x.NumberPart, AllDigit = x.NumberPart.All(Char.IsDigit) })
.Select(x => new
{
x.File,
Number = x.AllDigit ? int.Parse(x.NumberPart) : (int?)null
})
.OrderBy(x => x.Number.HasValue)
.ThenBy(x => x.Number ?? 0)
.Select(x => x.File);
If you even want that a static file-name is always on the top (as commented), you could use:
....
.OrderByDescending(x => x.File.Name.Equals("TestFile_cover.xml", StringComparison.CurrentCultureIgnoreCase))
.ThenBy(x => x.Number.HasValue)
.ThenBy(x => x.Number ?? 0)
.Select(x => x.File);