Eg: I have 2020M01 ,2019M12,2020M03 in datarow[].
How can i fetch max value i.e 2020M03
Your date format looks like it can be string sorted:
var dates = new System.Collections.Generic.List<string> { "2020M01", "2019M02", "2020M03" };
var max = dates.OrderByDescending(x => x).FirstOrDefault();
Or, as #panagiotis points out, Max() would also work:
var max = dates.Max();
This isn't an unusual format. Such formats ensure that date literals can be sorted alphabetically. YYYY-MM-DD and YYYYMMDD can be sorted alphabetically too.
This means that you can find the minimum or maximum value in a list simply by using the Min() or Max() LINQ functions, eg :
var months=new[]{ "2020M01" ,"2019M12","2020M03"};
var latestMonth=months.Max();
var earliestMonth=months.Min();
You say you have an array of DataRow, so I assume your dates must be in some column of the row
I'd thus say you need something like:
myDataRowArray.Max(ro => ro["nameOfYourDateColumn"].ToString());
If you mean that all your dates are in different columns of the same datarow, it's a bit more tricky. If there is nothing else in the row other than these dates, then it can be done with the row's ItemArray, an array of object representing each value of row's cells:
myDataRow.ItemArray.Max(elem => elem.ToString());
If there are some columns of the datarow that are your dates and some that are not, you're going to need to pull them out. Here I extract 3 different columns and put their values to a string array, then find the max:
new[] {
myRow["date1Column"].ToString(),
myRow["date2Column"].ToString(),
myRow["date3Column"].ToString()
}.Max();
Related
I have an SQL Server Reporting Services (SSRS) report that is using SQL order by sorting and returns the following for alphanumeric string data:
Value: 0.0
Value: 20.96
Value: 289.64
Value: 30.99
Value: 308.655
Value: -32296.32
Value: 34.844
Value: 38.95
Value: -697.38
Value: -703.48
Each string has the following format:
`Value: numeric data`
The SQL order by seems to sort as a string but ignores the minus sign before the numeric values.
I am using C# with LINQ to sort the strings to try to match that sorting:
var _sorted = _unsortedValues.OrderBy(x => x.Description);
I get:
Value: -32296.32
Value: -697.38
Value: -703.48
Value: 0.0
Value: 20.96
Value: 289.64
Value: 30.99
Value: 308.655
Value: 34.844
Value: 38.95
LINQ by default sorts the stings with all the minus values first ascending, followed by zero and then positive values
Any ideas on how to get the desired sorting to replicate SSRS sorting?
NOTE
I have other types of string in this report column that are sorted correctly.
e.g.
"Timestamp: data time data"
"Identifier: string data"
I suppose by LINQ here you mean regular LINQ to objects, not Entity Framework or LINQ to sql. How strings are sorted depends on comparer used, and you can pass whichever comparer you like to the OrderBy statement. So for example to get the sorting you want, you may do this:
var sorted = _unsortedValues.OrderBy(x => x.Description, StringComparer.InvariantCulture).ToArray();
Which will return the same order as your SQL statement.
At the same time if you will use another comparer, like this:
var sorted = _unsortedValues.OrderBy(x => x.Description, StringComparer.Ordinal).ToArray();
You will get the order like in your question (negative numbers first).
Why you get the order you get, but other people cannot reproduce that? That's because by default, CurrentCulture string comparer is used, and current culture might be different for different machines, so people get different results.
var sorted = _unsortedValues.OrderBy(x => x.Description, StringComparer.CurrentCulture).ToArray(); // this is what is done by default
As you can see your strings sorted in alphabetical order. No magic here. Number 289.64 goes before 30.99. If you want to sort by numbers inside strings, you should extract those numbers. You can use Regex, but simple Substring should do work here because all strings have the same prefix before number:
var startIndex = "Value: ".Length;
var _sorted = _unsortedValues
.OrderBy(x => Double.Parse(x.Description.Substring(startIndex)));
NOTE: Consider to get rid of Value: prefix on the server side, because it does not provide any real data.
I have a date range come like this,
string ActualReleaseDates ="7/8/2016, 7/9/2016, 7/11/2016,7/3/2016,7/10/2016,7/17/2016,7/24/2016,7/31/2016";
string NewsReleasedDate ="07/11/2016";
I want to check NewsReleaseDate is inside the ActualReleaseDates
But in the following code it return as a false.
if (ActualReleaseDates.Split(',').Contains(NewsReleasedDate.TrimStart(new Char[] { '0' })))
{
//some code here
}
The immediate problem is that after splitting your ActualReleaseDates string, there isn't an entry of "7/11/2016"... instead, there's an entry of " 7/11/2016"... note the space.
But more fundamentally, just trimming the start of NewsReleasedDate won't help if the value is something like "07/08/2016"... what you should be doing is handling these values as dates, rather than as strings:
Split ActualReleaseDates by comma, then parse each value (after trimming whitespace) in an appropriate format (which I suspect is M/d/yyyy) so that you get a List<DateTime>.
Parse NewsReleasedDate in the appropriate format, which I suspect is MM/dd/yyyy, so you get a DateTime.
See whether the parsed value from the second step occurs in the list from the first step.
(I'd personally recommend using Noda Time and parsing to LocalDate values, but I'm biased...)
Fundamentally, you're trying to see whether one date occurs in a list of dates... so make sure you get your data into its most appropriate representation as early as possible. Ideally, avoid using strings for this at all... we don't know where your data has come from, but if it started off in another representation and was converted into text, see if you can avoid that conversion.
The white space problem. You can use trim() and ' 7/11/2016' will be '7/11/2016'
var ActualReleaseDates = "7/8/2016, 7/9/2016, 7/11/2016,7/3/2016,7/10/2016,7/17/2016,7/24/2016,7/31/2016";
var NewsReleasedDate = "07/11/2016";
var splitActualReleaseDates = ActualReleaseDates.Split(',').Select(x => x.Trim());
if (splitActualReleaseDates.Contains(NewsReleasedDate.TrimStart(new Char[] { '0' })))
{
}
You can use linq to convert your strings into DateTime objects and compare them instead of strings
string ActualReleaseDates ="7/8/2016,7/9/2016,7/11/2016,7/3/2016,7/10/2016,7/17/2016,7/24/2016,7/31/2016";
string NewsReleasedDate ="07/11/2016";
var releaseDates = ActualReleaseDates.Split(',').Select(x => DateTime.Parse(x));
var newsReleased = DateTime.Parse(NewsReleaseDate);
if (releaseDates.Contains(newsReleased))
{
//some code here
}
please note that DateTime is parsed respectively to the current Culture. You can use DateTime.ParseExact if you want to specify exact date format.
You can Prase to DateTime before doing the query like this:
(I think this is the most accurate and guaranteed way to compare dates)
Func<string, DateTime> stringToDate = s => DateTime.ParseExact(s.Trim(), "M/d/yyyy",
CultureInfo.InvariantCulture);
DateTime newReleaseDateTime = stringToDate(NewsReleasedDate);
bool result = ActualReleaseDates.Split(',').Select(x => stringToDate(x))
.Contains(newReleaseDateTime);
It returns false because of the date 07/11/2016 stored in NewsReleasedDate is stored as string with a '0' at the begining. And in the ActualReleaseDates string you have white spaces between the ',' and numbers.
Try to rewrite theese strings like this :
ActualReleaseDates ="7/8/2016,7/9/2016,7/11/2016,7/3/2016,7/10/2016,7/17/2016,7/24/2016,7/31/2016"; // white spaces removed.
and the variable like this :
NewsReleasedDate ="7/11/2016"; // 0 removed
This is my code example :
string ActualReleaseDates = "7/8/2016,7/9/2016,7/11/2016,7/3/2016,7/10/2016,7/17/2016,7/24/2016,7/31/2016";
string NewsReleasedDate = "7/11/2016";
string[] dates = ActualReleaseDates.Split(',');
Console.WriteLine(dates.Contains(NewsReleasedDate));
This is not the best way to compare dates, you can use Date class which is usefull to do this kind of comparations.
If I have an excelsheet like
Name, age, ID;
Peter, 35, 123456;
Is there a way for me to locate that age is column numner 2, by searching for age in row 1, or similar?
What you can do is iterate through every column in the excel sheet and create a dictionary for every name/value pair. For example, 0 would map to Name, 1 would map to age and 2 would map to ID. From here, you may iterate through each row and for each column in that row look-up the name value pair (based on column ID). From there, you'll be able to determine the age.
Is there a way for me to locate that age is column numner 2, by searching for age in row 1, or similar?
Yes. Assuming the rows are really kept in the format you specified, separated by a comma, you can easily use string's Split method, and Linq's Select method:
string row = "Name, age, ID";
int columnNum = Array.IndexOf(row.Split(',')
.Select(x => x.Trim()).ToArray(), "age") + 1;
Explanation:
row.Split(',') - this method splits the string into an Array of strings: { "Name", "age", "ID" }
.Select(x => x.Trim()).ToArray() - this expression use LINQ to eliminate all the unnecessary spaces in the column Name (the method Trim() removes spaces at the beginning and at the end of the string).
Array.IndexOf - This method finds the index of the desired value ("age") within the array.
Indexes in C# begins at zero. namely, the index of "Name" is 0, and the index of "age" is actually 1 (and so on). To solve this I simply add 1 to the number returned by "IndexOf".
I'm warmly recommend to read any C# basic tutorial. it's all there :)
Check the example of string search in Excel from MSDN:
http://msdn.microsoft.com/en-us/library/e4x1k99a.aspx
I have a set of strings, the strings are in format: Ticks then an underscore than a Guid.
So for example: Ticks_Guid would be the string. The ticks are actually DateTime.MaxTicks - the ticks of some date (aside: I do this to get the string to naturally show up in descending order).
Using only CompareTo is there a way to get the strings that are within a certain date range?
Since you say you have the strings in naturally descending order, I assume you have a fixed-width section for the ticks component of the string (otherwise the descending order bit won't work). The easiest comparison therefore would be to create two similarly formatted string; one for the tick value of the earlier date combined with an empty guid (all 0s) and another for the latter date combined with a guid that is all 0xFF, and then find the strings that sort between those in raw code-point order.
I'd just compare if the ticks are in between your dates to check in an if-statement:
ArrayList a = new ArrayList();
string b = "345678_lalala";
string c = "429817_lalelu";
a.Add(b);
a.Add(c);
//date to check
string begin = "298918";
string end = "419812";
ArrayList outputList = new ArrayList();
foreach (string str in a)
{
if (str.CompareTo(begin) == 1 && str.CompareTo(end) == -1)
{
outputList.Add(str);
}
}
I have a C# list collection that I'm trying to sort. The strings that I'm trying to sort are dates "10/19/2009","10/20/2009"...etc. The sort method on my list will sort the dates but the problem is when a day has one digit, like "10/2/2009". When this happens the order is off. It will go "10/19/2009","10/20/2009","11/10/2009","11/2/2009","11/21/2009"..etc. This is ordering them wrong because it sees the two as greater than the 1 in 10. How can I correct this?
thanks
The problem is they're strings, but you want to sort them by dates. Use a comparison function that converts them to dates before comparing. Something like this:
List<string> strings = new List<string>();
// TODO: fill the list
strings.Sort((x, y) => DateTime.Parse(x).CompareTo(DateTime.Parse(y)));
Assuming all your strings will parse:
MyList.OrderBy(d => DateTime.Parse(d));
Otherwise, you might need to use ParseExact() or something a little more complicated.
write a compare method to convert "10/2/2009" to a date then compare
I wanted to see how well I could outperform Chris's solution with my own IComparer. The difference was negligible. To sort the same list of one million dates, my solution took 63.2 seconds, and Chris's took 66.2 seconds.
/// <summary>
/// Date strings must be in the format [M]M/[D]D/YYYY
/// </summary>
class DateStringComparer : IComparer<string>
{
private static char[] slash = { '/' };
public int Compare(string Date1, string Date2)
{
// get date component strings
string[] strings1 = Date1.Split(slash);
string[] strings2 = Date2.Split(slash);
// get date component numbers
int[] values1 = { Convert.ToInt32(strings1[0]),
Convert.ToInt32(strings1[1]),
Convert.ToInt32(strings1[2]) };
int[] values2 = { Convert.ToInt32(strings2[0]),
Convert.ToInt32(strings2[1]),
Convert.ToInt32(strings2[2]) };
// compare year, month, day
if (values1[2] == values2[2])
if (values1[0] == values2[0])
return values1[1].CompareTo(values2[1]);
else
return values1[0].CompareTo(values2[0]);
else
return values1[2].CompareTo(values2[2]);
}
}
As for sorting the dates as pre-existing DateTime instances, that took 252 milliseconds.
You need to either use a sort specific for dates, or use something like Natural Sort.
Parse the strings to DateTime objects and use DateTime.Compare.
Chris beat me to it!
If you care about performance and if that is possible for you, you would preferably sort your dates before you generate the strings. You would then use the date objects directly for the sort.
You would then save time manipulating strings back and forth.