1
var myDic = new SortedDictionary<DateTime,int> () 
                { { new DateTime(0), 0 },
                  { new DateTime(1), 1 },
                  { new DateTime(2), 1 },
                  { new DateTime(3), 0 },
                  { new DateTime(4), 0 },
                  { new DateTime(5), 2 }
                };

How can group these items (with a LINQ request) like this :

group 1 : 
  startDate: 0, endDate:0, value:0
group 2 : 
  startDate: 1, endDate:2, value:1
group 3 : 
  startDate: 3, endDate:4, value:0
group 4 : 
  startDate: 5, endDate:5, value:2

group are defined by contiguous date and same values.

Is it possible with a groupby ?

ekad
  • 14,436
  • 26
  • 44
  • 46
scanpat
  • 309
  • 1
  • 4
  • 8
  • 1
    As a general rule, LINQ either operates on the entire list or a single element of it. You're asking for it to act based on what's around it, but not the whole list, which is not something it's good at. – Bobson Nov 12 '12 at 20:12

2 Answers2

2

Just use a keyGenerating function. This example presumes your dates are already ordered in the source with no gaps.

int currentValue = 0;
int groupCounter = 0;

Func<KeyValuePair<DateTime, int>, int> keyGenerator = kvp =>
{
  if (kvp.Value != currentValue)
  {
    groupCounter += 1;
    currentValue = kvp.Value;
  }
  return groupCounter;
}

List<IGrouping<int, KeyValuePair<DateTime, int>> groups =
  myDictionary.GroupBy(keyGenerator).ToList();
Amy B
  • 108,202
  • 21
  • 135
  • 185
1

It looks like you are trying to group sequential dates over changes in the value. I don't think you should use linq for the grouping. Instead you should use linq to order the dates and iterate over that sorted list to create your groups.

Addition 1 While you may be able to build your collections with by using .Aggregate(). I still think that is the wrong approach.

Does your data have to enter this function as a SortedDictionary? I'm just guessing, but these are probably records ordered chronologically.

If so, do this:

    public class Record
    {
        public DateTime Date { get; set; }
        public int Value { get; set; }
    }

    public class Grouper
    {
        public IEnumerable<IEnumerable<Record>> GroupRecords(IEnumerable<Record> sortedRecords)
        {
            var groupedRecords = new List<List<Record>>();
            var recordGroup = new List<Record>();
            groupedRecords.Add(recordGroup);

            foreach (var record in sortedRecords)
            {
                if (recordGroup.Count > 0 && recordGroup.First().Value != record.Value)
                {
                    recordGroup = new List<Record>();
                    groupedRecords.Add(recordGroup);
                }

                recordGroup.Add(record);
            }

            return groupedRecords;
        }
    }
BenMorel
  • 34,448
  • 50
  • 182
  • 322
Josh C.
  • 4,303
  • 5
  • 30
  • 51
  • So it is not possible with a GroupBy linq request ? Is it possible with a TakeWhile ? – scanpat Nov 12 '12 at 20:00
  • You might be able to do something with Aggregate(), but I think it's the wrong approach. I am editing my post. Please see the additions. – Josh C. Nov 12 '12 at 20:07