Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
558 views
in Technique[技术] by (71.8m points)

c# - Combining consecutive dates into ranges

I have a List of objects

public class sample
{
 public DateTime Date;
 public string content;
}

I want to be able to create a list of new objects

public class sampleWithIntervals
{
 public DateTime startDate;
 public DateTime endDate;
 public string content;
}

The sample objects should be grouped into intervals based on the content. The intervals can include only those dates that are included in the original sample list. I dont know how to do this in Linq.

Sample data:

{"10/1/2013", "x"}
{"10/2/2013", "x"}
{"10/2/2013", "y"}
{"10/3/2013", "x"}
{"10/3/2013", "y"}
{"10/10/2013", "x"}
{"10/11/2013", "x"}
{"10/15/2013", "y"}
{"10/16/2013", "y"}
{"10/20/2013", "y"}

This should give me 
{"10/1/2013","10/3/2013", "x"}
{"10/2/2013","10/3/2013", "y"}
{"10/10/2013","10/11/2013", "x"}
{"10/15/2013","10/16/2013", "y"}
{"10/20/2013","10/20/2013", "y"}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Here's a non-Linq way to do it:

List<sampleWithIntervals> groups = new List<sampleWithIntervals>();  
sampleWithIntervals curGroup = null;

foreach(sample s in samples.OrderBy(sa => sa.content).ThenBy(sa => sa.Date))
{
    if(curGroup == null || // first group
        s.Date != curGroup.endDate.AddDays(1) ||
        s.content != curGroup.content   // new group
      ) 
    {
        curGroup = new sampleWithIntervals() {startDate = s.Date, endDate = s.Date, content = s.content};
        groups.Add(curGroup);
    }
    else
    {
        // add to current group
        curGroup.endDate = s.Date;
    }
}

You can do this with Linq using a trick that groups the items by the date minus the index to group consecutive items:

samples.OrderBy(s => s.content)   
       .ThenBy(s => s.Date)
       // select each item with its index
       .Select ((s, i) => new {sample = s, index = i})  
       // group by date miuns index to group consecutive items
       .GroupBy(si => new {date = si.sample.Date.AddDays(-si.index), content = si.sample.content})  
       // get the min, max, and content of each group
       .Select(g => new sampleWithIntervals() {
                        startDate = g.Min(s => s.sample.Date), 
                        endDate = g.Max(s => s.sample.Date), 
                        content = g.First().sample.content
                        })

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...