Sorting months in a list - c#

I have a list of strings which contains months of the year. I need to be able to sort this list so the months are in order by month, not alphabetically. I have been searching for awhile but I can't see to wrap my head around any of the solutions I've found.
Here's an example of how the months might be added. They are added dynamically based off of fields in a SharePoint list so they can be in any order and can have duplicates (I am removing these with Distinct()).
List<string> monthList = new List<string>();
monthList.Add("June");
monthList.Add("February");
monthList.Add("August");
Would like to reorder this to:
February
June
August

You could parse the string into a DateTime and then sort using the month integer property. See here for supported month names: http://msdn.microsoft.com/en-us/library/system.globalization.datetimeformatinfo.monthnames.aspx
Something like this:
var sortedMonths = monthList
.Select(x => new { Name = x, Sort = DateTime.ParseExact(x, "MMMM", CultureInfo.InvariantCulture) })
.OrderBy(x => x.Sort.Month)
.Select(x => x.Name)
.ToArray();

You can parse month names into dates (it assumes the current year and day 1):
monthList = monthList.OrderBy(s=> DateTime.ParseExact(s, "MMMM", new CultureInfo("en-US"))).ToList();

You can use a Dictionary<int,string> instead, using the int as a month number for sorting, then sorting by key.
IDictionary<int,string> monthList = new Dictionary<int,string>();
monthList.Add(6, "June");
monthList.Add(2, "February");
monthList.Add(8, "August");
var sorted = monthList.OrderBy(item => item.Key);

If you insist on having a list of only strings representing months, then you must use another data source to retrieve the index of that month by which you can sort the list. For example, you could populate a dictionary with the month names as string keys and an int index as the value. You can then use the overloaded method List<T>.Sort(Comparison<T>) and pass in a comparison function that returns the index of the months by name (by passing them into the dictionary).
However, I would recommend not using a raw string in the first place, but rather a more structured data type representing a month. You can then embed the index in the data structure itself and sort based on that value, thus giving you a more self-contained solution.

You need a SortedList<> .. such as
SortedList<int,string> monthList=new SortedList<int,string>();
monthList.Add(6,"June");
monthList.Add(2,"February");
monthList.Add(8,"August");
IList<string> sortedMonthList=monthList.Values;
then use sortedMonthList for the rest.
This could be improved by using seldon's answer to create a function, just like
public static int MonthNumFromName(String monthname)
{ ... }
and then use
monthList.Add(MonthNumFromName("June"),"June");
above.

Well, I guess there aren't any sorting techniques for this with just pure month as string.
You can just use a Dictionary<int, string> and use the int to sort your months.
If I haven't mistaken, you are actually having a List of months as string, then why don't you do this?
List<string> months = new List<string> { "January", "February", ..., "December" };
var yourSortedMonthsInYourOriginalList = months.Where(m =>
originalList.Any(o => o == m)).ToList();

You can build your own sort class:
static void Main(string[] args)
{
List<string> monthList = new List<string>();
monthList.Add("June");
monthList.Add("February");
monthList.Add("August");
monthList.Sort(new _mysort());
}
private class _mysort : IComparer<string>
{
public int Compare(string x, string y)
{
if (x=="February" && y=="June")
{
return -1;
}
return 0;
}
}
But i think you should use an Enum, and convert it to string, then you can use the numeric to sort it.
enum months
{
Jan =0,
Feb =1
}
like:
List<months> mlist = new List<months>() { months.Feb, months.Jan };
//sort
mlist = mlist.OrderBy(e => (int)e).ToList();
//print
mlist.ForEach(e => Console.WriteLine(e.ToString()));

Create an enum and assign int values for each month. Sort that thing with linq.

Related

List with dates, times and a string ref

I have a sorted list of data to populate a gridview control.
The list is ordered by datetime
I need to find the most recent 3 times per unique ref within each day (there may be more than 1 unique refs within a day). If there is only 1 ref row within a day then it is to be ignored.
I suppose it needs to be chunked into days and refs, then ordered by most recent with a count of refs within that 'chunk'. Any ideas appreciated.
It's a standard list of objects (the object has Date, Time and Ref properties) as:
private List<Reading> _listReadings = new List<Reading>();
and is bound to a grid:
DataRow newRow = MyTable.NewRow();
newRow.ItemArray = new object[]
{
new
DateTime(_listReadings.TimeStamp.Year,listReadings.TimeStamp.Month),
GetTime(_listReadings.TimeStamp),
_listReadings.Ref,
};
MyTable.Rows.Add(newRow);
Given a backing source of List<Reading>,
Group your source data by day using GroupBy
For-each day (the value in the group):
Group your source data by ref using GroupBy
Test if the group has 3+ values, or filter the ones that do not (Where and Count)
Order by datetimes of the values using OrderByDescending (latest is first)
Take 3 dates
So something like this:
public static IEnumerable<Reading> Filter(List<Reading> readings)
{
List<Reading> result = new List<Reading>();
var dayGroupings = readings.GroupBy(r => r.Day);
foreach (var dayGroup in dayGroupings)
{
var refGroupings = dayGroup.GroupBy(g => g.Ref);
foreach (var refGroup in refGroupings.Where(g => g.Count() >= 3))
{
result.AddRange(refGroup.OrderByDescending(g => g.Time).Take(3));
}
}
return result;
}

LINQ - Decide which date is the oldest for each record

Hey i got a list having many records inside, there are 3 DateTime inside (nullable). What i need is to get a LINQ expression determining which one of this three is the latest then select that record and check again. Here is the code how i created the List.
List<ActivityJoinUserTopicVote> ActivityList = new List<ActivityJoinUserTopicVote>();
foreach (var p in postdate)
{
ActivityList.Add(new ActivityJoinUserTopicVote(p.R_Posted, p.Forum_id, p.R_Posted_By, p.R_Message, p.Reply_ID, p.Topic_ID, p.User));
}
foreach (var v in votedate)
{
ActivityList.Add(new ActivityJoinUserTopicVote(v.data, v.Topic_ID, v.vote, v.Member_ID, v.Vote_Member_ID));
}
foreach (var t in topicdate)
{
ActivityList.Add(new ActivityJoinUserTopicVote(t.T_date, t.Forum_id, t.T_Originator, t.T_Replies, t.T_ukaz, t.Topic_ID, t.User, t.T_Url, t.T_subject));
}
return ActivityList;
Before returning the ActivityList i need it to determine which one was the most recent and sort it this way. Maybe i could do this somehow while creating the list? The problem is i got 3 different columns inside i need to check in (R_Posted, data and T_date)
Get the maximum of 3 dates using ticks, and sort by that value:
Helper:
private long MaxOfThreeDate(DateTime? date1, DateTime? date2, DateTime? date3)
{
long max1 = Math.Max(date1.GetValueOrDefault().Ticks, date2.GetValueOrDefault().Ticks);
return Math.Max(max1, date3.GetValueOrDefault().Ticks);
}
Usage:
return ActivityList.OrderByDescending(x => MaxOfThreeDate(x.data, x.R_Posted, x.T_date)).ToList();
replace
return ActivityList;
with
return ActivityList.OrderByDescending(x => x.data.HasValue ? x.data : ( x.R_Posted.HasValue ? x.R_Posted : x.T_date)).ToList();
or
return ActivityList.OrderByDescending(x => new DateTime?[]{ x.data, x.R_Posted, x.T_date}.Max()).ToList();
to return the ActivityList sorted by the date fields descending
You can get the most recent one using this
var list = ActivityList.OrderByDescending(x=>x.Date).First();

C# Remove duplicate times within range and mark them

So ive come across a slight issue with Lists in C#
I have a List that has some very similar dates. Now what i need to do is remove duplicates but where a duplicate is if its within one minute of another time, so not exactly the same.
As well as this, if there were duplicates of a specific time the object should have a flag saying so in the final list.
Now i can see how this could be done with lots of for loop, but i was hoping theres a nice way with LINQ to make this simple. So far my attempts havent been going very well though.
As an example a list of the following dates:
21/12/12 12:13:00
21/12/12 12:13:20
13/12/12 10:13:00
21/10/15 07:13:00
should turn into the list of DateDuplicate objects:
{date = 21/12/12 12:13:00, isDuplcicate=true}
{date = 13/12/12 10:13:00, isDuplcicate=false}
{date = 21/10/15 07:13:00, isDuplcicate=false}
public class DateDuplicate{
public DateTime date;
public bool isDuplicate = false;
}
List<DateDuplicate> RemoveAndMark(List<DateTime> dates){
///something nice here hopefully
}
thanks for any help!
Try this
List<DateDuplicate> RemoveAndMark(List<DateTime> dates)
{
var dateValues = dates.GroupBy(y => new { AddHours = y.Date.Date.AddHours(y.Hour), y.Minute}).Select(x =>
new DateDuplicate {isDuplicate = x.Count() > 1, date = x.Key.AddHours.AddMinutes(x.Key.Minute)}
);
return dateValues;
}

Creating and Displaying multiple arrays simultaniously C#

I'm new to C# and programming as a whole and I've been unable to come up with a solution to what I want to do. I want to be able to create a way to display several arrays containing elements from three external text files with values on each line (e.g. #"Files\Column1.txt", #"Files\Column2.txt" #"Files\Column3.txt"). They then need to be displayed like this in the command line:
https://www.dropbox.com/s/0telh1ils201wpy/Untitled.png?dl=0
I also need to be able to sort each column individually (e.g. column 3 from lowest to highest).
I've probably explained this horribly but I'm not sure how else to put it! Any possible solutions will be greatly appreciated!
One way to do it would be to store the corresponding items from each file in a Tuple, and then store those in a List. This way the items will all stay together, but you can sort your list on any of the Tuple fields. If you were doing anything more detailed with these items, I would suggest creating a simple class to store them, so the code would be more maintainable.
Something like:
public class Item
{
public DayOfWeek Day { get; set; }
public DateTime Date { get; set; }
public string Value { get; set; }
}
The example below could easily be converted to use such a class, but for now it uses a Tuple<string, string, string>. As an intermediate step, you could easily convert the items as you create the Tuple to get more strongly-typed versions, for example, you could have Tuple<DayOfWeek, DateTime, string>.
Here's the sample code for reading your file items into a list, and how to sort on each item type:
public static void Main()
{
// For testing sake, I created some dummy files
var file1 = #"D:\Public\Temp\File1.txt";
var file2 = #"D:\Public\Temp\File2.txt";
var file3 = #"D:\Public\Temp\File3.txt";
// Validation that files exist and have same number
// of items is intentionally left out for the example
// Read the contents of each file into a separate variable
var days = File.ReadAllLines(file1);
var dates = File.ReadAllLines(file2);
var values = File.ReadAllLines(file3);
var itemCount = days.Length;
// The list of items read from each file
var fileItems = new List<Tuple<string, string, string>>();
// Add a new item for each line in each file
for (int i = 0; i < itemCount; i++)
{
fileItems.Add(new Tuple<string, string, string>(
days[i], dates[i], values[i]));
}
// Display the items in console window
fileItems.ForEach(item =>
Console.WriteLine("{0} {1} = {2}",
item.Item1, item.Item2, item.Item3));
// Example for how to order the items:
// By days
fileItems = fileItems.OrderBy(item => item.Item1).ToList();
// By dates
fileItems = fileItems.OrderBy(item => item.Item2).ToList();
// By values
fileItems = fileItems.OrderBy(item => item.Item3).ToList();
// Order by descending
fileItems = fileItems.OrderByDescending(item => item.Item1).ToList();
// Show the values based on the last ordering
fileItems.ForEach(item =>
Console.WriteLine("{0} {1} = {2}",
item.Item1, item.Item2, item.Item3));
}

Incorrect array data returning from Linq query expression

See i have this following code below, at line no.9 i'm calculating some dates to move forward, so im using AddDays method but in return i'm getting all dates same for all rows.
If i do AddDays(6) like this then it is returning correctly by moving all dates by 6 days.
How should i do it for adding days according to my logic at this point.
[DataContract]
public class JQGridRow
{
[DataMember]
public long id;
[DataMember]
public object[] cell;
}
var sortedItems = invBatch.ListOfItems.OrderBy(i => i.RunDateIndex);//This will return IEnumerable<Class> List
DateTime startDate = DateTime.Parse(lblStartDate.Text);
JQGrid.JQGridRow[] rowData = (
from i in sortedItems
select new JQGrid.JQGridRow() {
id = i.ID,
cell = new string[] {
i.ID.ToString(),
i.Status.ToString(),
i.StatusTitle,
i.RunDate.AddDays((startDate.Subtract(i.RunDate)).Days+1).ToString(Utility.DATE_FORMAT),
//Here in above line the array returning same values for all columns of this row
i.StartTimeString,
i.EndTimeString,
i.EndTime.ToString(),
}}).ToArray();
The dates are all same and equal the next day after startDate because you calculate them as such.
i.RunDate.AddDays((startDate.Subtract(i.RunDate)).Days+1)
Rounding to whole day, you compute RunDate+(startDate-RunDate+1) = startDate + 1. i.RunDate does not matter.

Categories

Resources