2010-03-23 3 views
4

개체 목록이 있습니다. 각 개체에는 정수 값과 월 및 연도 값을 포함하는 DateTime 변수가 있습니다. 목록을 탐색하고 누락 된 월 (수량 0)을 추가하여 목록에 추가하여 모든 연속 월이 목록에 표시되도록하고 싶습니다. 이것을 달성하는 가장 좋은 방법은 무엇입니까?.NET을 사용하여 요소를 추가하는 통과 목록

예 : 원래 목록

Jan10 {3} {Feb10, 4}, {Apr10, 2}, {May10, 2}, {Aug10, 3}, {Sep10 -3} {Oct10 6}, {Nov10, 3}, {Dec10, 7}, {Feb11, 3}

새로운 목록

{Jan10, 3}, {Feb10, 4}, {Mar10 0 }, {Apr10, 2}, {5 월 10 일, 2}, {Jun10, 0} {Oct10, 3}, {Oct10, 6}, {Nov10, 3}, {Dec10, 7}, {J AN11, 0}, {Feb11는 3}

+1

월 및 일년이 포함 된 * DateTime * 변수는 어떻게 있습니까? 이 클래스는 Date 형의 필드/프로퍼티를 가지며, 그 일을 유지하지 못한다. 또는 문자열 ("Apr10") 필드/속성입니까? –

+0

이 목록은 하루로되어 있습니까? – JaredPar

+0

@Addie 당신이 'Jan10'대신에'Jan2010'을 사용했다면 사람들에게 분명히 드러날 것입니다.''Janurary'의 10 번째를 의미하는 사람들이 많이 생겼습니다. 귀하의 텍스트에. – Tanzelax

답변

3

한 가지 알고리즘은 이전 및 현재 달의 트랙을 유지하는 것입니다. 이전과 현재의 차이가 1 개월이면 결과에 전류를 추가하십시오. 차이가 1 개월 이상인 경우 누락 된 달을 먼저 추가 한 후 현재 달을 복사하십시오.

Foo prev = months.First(); 
List<Foo> result = new List<Foo> { prev }; 
foreach (Foo foo in months.Skip(1)) 
{ 
    DateTime month = prev.Month; 
    while (true) 
    { 
     month = month.AddMonths(1); 
     if (month >= foo.Month) 
     { 
      break; 
     } 
     result.Add(new Foo { Month = month, Count = 0 }); 
    } 
    result.Add(foo); 
    prev = foo; 
} 

결과 :

01-01-2010 00:00:00: 3 
01-02-2010 00:00:00: 4 
01-03-2010 00:00:00: 0 
01-04-2010 00:00:00: 2 
01-05-2010 00:00:00: 2 
01-06-2010 00:00:00: 0 
01-07-2010 00:00:00: 0 
01-08-2010 00:00:00: 3 
01-09-2010 00:00:00: -3 
01-10-2010 00:00:00: 6 
01-11-2010 00:00:00: 3 
01-12-2010 00:00:00: 7 
01-01-2011 00:00:00: 0 
01-02-2011 00:00:00: 3 

다른 코드이 컴파일 만드는 데 필요한 :

class Foo 
{ 
    public DateTime Month { get; set; } 
    public int Count { get; set; } 
} 

List<Foo> months = new List<Foo> 
{ 
    new Foo{ Month = new DateTime(2010, 1, 1), Count = 3 }, 
    new Foo{ Month = new DateTime(2010, 2, 1), Count = 4 }, 
    new Foo{ Month = new DateTime(2010, 4, 1), Count = 2 }, 
    new Foo{ Month = new DateTime(2010, 5, 1), Count = 2 }, 
    new Foo{ Month = new DateTime(2010, 8, 1), Count = 3 }, 
    new Foo{ Month = new DateTime(2010, 9, 1), Count = -3 }, 
    new Foo{ Month = new DateTime(2010, 10, 1), Count = 6 }, 
    new Foo{ Month = new DateTime(2010, 11, 1), Count = 3 }, 
    new Foo{ Month = new DateTime(2010, 12, 1), Count = 7 }, 
    new Foo{ Month = new DateTime(2011, 2, 1), Count = 3 } 
}; 

참고 : 원래 목록이 비어 있지만 어디 사건을 처리하지 않은 단순화하기 위해 당신 프로덕션 코드에서이 작업을 수행해야합니다.

+0

이것은 사양에 맞으며 매우 간단하며 잘 수행 할 수 있습니다. –

+0

+1에 대한 작품. : p – Tanzelax

+0

감사합니다. 에 딱 맞다. – Addie

1
var months = new [] { "Jan", "Feb", "Mar", ... }; 
var yourList = ...; 
var result = months.Select(x => { 
    var yourEntry = yourList.SingleOrDefault(y => y.Month = x); 
    if (yourEntry != null) { 
    return yourEntry; 
    } else { 
    return new ...; 
    } 
}); 
3

구조가 List<Tuple<DateTime,int>>으로 유지되는 것으로 가정합니다.

var oldList = GetTheStartList(); 
var map = oldList.ToDictionary(x => x.Item1.Month); 

// Create an entry with 0 for every month 1-12 in this year 
// and reduce it to just the months which don't already 
// exist 
var missing = 
    Enumerable.Range(1,12) 
    .Where(x => !map.ContainsKey(x)) 
    .Select(x => Tuple.Create(new DateTime(2010, x,0),0)) 

// Combine the missing list with the original list, sort by 
// month 
var all = 
    oldList 
    .Concat(missing) 
    .OrderBy(x => x.Item1.Month) 
    .ToList(); 
+0

) Jan10과 Jan11이 같은 목록에 있습니다. – Tanzelax

+0

@Tanzelax, 오타처럼 보입니다. 확인을 위해 덧글을 추가하겠습니다. – JaredPar

+0

아니요, 그는 2010 년 1 월에서 2011 년 2 월까지 최종 목록에서 14 가지 요소를 원합니다. – Tanzelax

0

한 가지 방법은 당신이 "제외"확장 방법을 사용하여 기존 목록에 추가 "필러"개체의 목록을 만들 수 있습니다, 개체의 IEqualityComparer <>를 구현하는 것입니다. 정렬의 내가 "날짜 시간"달 올바르게 이해 해요 경우

public class MyClass 
{ 
    public DateTime MonthYear { get; set; } 
    public int Quantity { get; set; } 
} 

public class MyClassEqualityComparer : IEqualityComparer<MyClass> 
{ 
    #region IEqualityComparer<MyClass> Members 

    public bool Equals(MyClass x, MyClass y) 
    { 
     return x.MonthYear == y.MonthYear; 
    } 

    public int GetHashCode(MyClass obj) 
    { 
     return obj.MonthYear.GetHashCode(); 
    } 

    #endregion 
} 

그리고 다음은이

// let this be your real list of objects  
List<MyClass> myClasses = new List<MyClass>() 
{ 
    new MyClass() { MonthYear = new DateTime (2010,1,1), Quantity = 3}, 
    new MyClass() { MonthYear = new DateTime (2010,12,1), Quantity = 2} 
}; 

List<MyClass> fillerClasses = new List<MyClass>(); 
for (int i = 1; i < 12; i++) 
{ 
    MyClass filler = new MyClass() { Quantity = 0, MonthYear = new DateTime(2010, i, 1) }; 
    fillerClasses.Add(filler); 
} 

myClasses.AddRange(fillerClasses.Except(myClasses, new MyClassEqualityComparer())); 
+0

오, 내 솔루션과 비슷한 :) – Nagg

0

처럼 뭔가를 할 수처럼 :

for (int i = 0; i < 12; i++) 
     if (!original.Any(n => n.DateTimePropery.Month == i)) 
      original.Add(new MyClass {DateTimePropery = new DateTime(2010, i, 1), IntQuantity = 0}); 
    var sorted = original.OrderBy(n => n.DateTimePropery.Month); 
0

고려 년, 속도와 확장 성 그것은 열거 가능한 확장으로 할 수 있습니다 (아마도 일반 속성 선택기를 사용하는 것조차도).

public static class Extensions 
{ 
    public static IEnumerable<Tuple<DateTime, int>> FillMissing(this IEnumerable<Tuple<DateTime, int>> list) 
    { 
     if(list.Count() == 0) 
      yield break; 
     DateTime lastDate = list.First().Item1; 
     foreach(var tuple in list) 
     { 
      lastDate = lastDate.AddMonths(1); 
      while(lastDate < tuple.Item1) 
      { 
       yield return new Tuple<DateTime, int>(lastDate, 0); 
       lastDate = lastDate.AddMonths(1); 
      } 
      yield return tuple; 
      lastDate = tuple.Item1; 
     } 
    } 
} 

및 예제 형태 :

private List<Tuple<DateTime, int>> items = new List<Tuple<DateTime, int>>() 
    { 
     new Tuple<DateTime, int>(new DateTime(2010, 1, 1), 3), 
     new Tuple<DateTime, int>(new DateTime(2010, 2, 1), 4), 
     new Tuple<DateTime, int>(new DateTime(2010, 4, 1), 2), 
     new Tuple<DateTime, int>(new DateTime(2010, 5, 1), 2), 
     new Tuple<DateTime, int>(new DateTime(2010, 8, 1), 3), 
     new Tuple<DateTime, int>(new DateTime(2010, 9, 1), -3), 
     new Tuple<DateTime, int>(new DateTime(2010, 10, 1), 6), 
     new Tuple<DateTime, int>(new DateTime(2010, 11, 1), 3), 
     new Tuple<DateTime, int>(new DateTime(2010, 12, 1), 7), 
     new Tuple<DateTime, int>(new DateTime(2011, 2, 1), 3) 
    }; 

    public Form1() 
    { 
     InitializeComponent(); 
     var list = items.FillMissing(); 
     foreach(var element in list) 
     { 
      textBox1.Text += Environment.NewLine + element.Item1.ToString() + " - " + element.Item2.ToString(); 
     } 
    } 

포함하는 텍스트 상자가 발생합니다 : 날짜가 이미 실행 FillMissing 전에 주문한 달 목록에 잘린 경우 ,이 방법을 고려하시기 바랍니다

2010-01-01 00:00:00 - 3 
2010-02-01 00:00:00 - 4 
2010-03-01 00:00:00 - 0 
2010-04-01 00:00:00 - 2 
2010-05-01 00:00:00 - 2 
2010-06-01 00:00:00 - 0 
2010-07-01 00:00:00 - 0 
2010-08-01 00:00:00 - 3 
2010-09-01 00:00:00 - -3 
2010-10-01 00:00:00 - 6 
2010-11-01 00:00:00 - 3 
2010-12-01 00:00:00 - 7 
2011-01-01 00:00:00 - 0 
2011-02-01 00:00:00 - 3