2014-06-25 1 views
0

두 개의 목록 하위 속성이 포함 된 항목 목록이 있습니다. 두 개의 하위 속성이 결합 된 결과 인 모든 (고유 한) 값을 가져와야합니다 상위 클래스에서만 조인).두 개의 하위 목록 결합을 기반으로 한 단일 목록 가져 오기

클래스

public class Calendar 
{ 
    public List<int> Months { get; set; } 
    public List<int> Days { get; set; } 
    public int Id { get; set; } 

    public Calendar(int id) 
    { 
     Months = new List<int>();  
     Days = new List<int>(); 
     this.Id = id; 
    } 
} 

나는 달력 개체의 목록을 가지고 있고, 나는 전체 컬렉션에서 월/일 조합의 목록을 얻을 필요가 : 아래는 인위적인 예입니다. 나는 두 개의 SelectMany 옵션에 가입하여이 일을 처리했다 :이 쿼리를 수행하는 더 효율적인 방법을

그래서이 방법이 작동
Day Month 
1 1 
6 1 
1 2 
6 2 
15 2 
6 4 
15 4 

하지만이 :

var years = new List<Calendar>(); 

var cal2001 = new Calendar(1); 
cal2001.Months = new List<int>() { 1, 2}; 
cal2001.Days = new List<int>() { 1, 6 }; 
years.Add(cal2001); 

var cal2002 = new Calendar(2); 
cal2002.Months = new List<int>() { 2, 4}; 
cal2002.Days = new List<int>() { 6, 15 }; 
years.Add(cal2002); 

var items = (from M in years.SelectMany(Y => Y.Months, (Y, result) => new { Month = result, Id = Y.Id }) 
      join D in years.SelectMany(Y => Y.Days, (Y, result) => new { Day = result, Id = Y.Id }) on M.Id equals D.Id 
      select new { Day = D.Day, Month = M.Month }).Distinct(); 

items.Dump(); //Dump items to output in Linqpad. 

이 원하는 출력을 제공 ?

답변

3

이 시도 :

years.SelectMany(y=> from d in y.Days 
        from m in y.Months 
        select new{d,m}) // cross join 
    .Distinct() 
    .Dump(); 

이 같은 출력을 제공합니다.

또한 귀하의 요청은 입니다. 달성하고자하는 것은 실제로입니까? 같은 해에 여러 개의 캘린더를 사용하면 펑키 한 결과를 얻을 수 있습니다.

var years = new []{ 
    new Calendar(2001){ Months = { 1 }, Days= { 2 }}, 
    new Calendar(2001){ Months = { 3 }, Days= { 4 }}, 
}; 

=>이주는 (2,1), (4,1), (2,3), (4,3)이 의도 된 결과입니다 : 예를 들어, 귀하의 요청을 다시 시도 ? (예인 경우 요청이 작동하지 않습니다)

+0

. 이것은 치료를 나타납니다! 실제로 "연도"는 실제로 ID이므로 괜찮습니다. 명확하게하기 위해 예제 코드를 업데이트 하겠지만 솔루션은 제 요구 사항에 맞게 잘 작동합니다. –

+0

@Olivier : 마지막 예제가 네 가지 요소를주는 이유는 무엇입니까? 나는 그것을 시도하고 그것을 정확히 무엇을 기대했다. 'SelectMany'는 해 배열의 각 원소에 대해 독립적으로 작동 할 것이며, 둘 이상의 원소가 같은 해를 갖는 지 신경 쓰지 않을 것입니다. 그리고 네, 사실 확인을 위해 그것을 달렸고 열거 형에서 두 가지 결과를 얻었습니다. 그것이 OP와 관련이있는 것은 아니지만,이 경우보다 정확한 답변을 업데이트하는 것이 좋을 것입니다. :) – Chris

+0

@Chris yep, 내 요청에 따라 2 가지 결과 만 표시되지만 (Obsidian Phoenix가 질문에 제시 한) 원래 요청은 4 가지 결과를 산출합니다! – Olivier

0

IEqualityComparer을 구현하면 Distinct을 사용하여 중복 된 내용을 제거 할 수 있습니다. 나는 당신이 가지고있는 익명의 타입에 해당하는 이름 클래스 DateEntry을 소개했다. 또한 결과를 정렬 할 수 있도록 IComparable을 구현했습니다.

public class DateEntryComparer : IEqualityComparer<DateEntry> 
{ 
    public bool Equals(DateEntry lhs, DateEntry rhs) 
    { 
     return lhs.Day == rhs.Day && lhs.Month == rhs.Month; 
    } 

    public int GetHashCode(DateEntry entry) 
    { 
     return entry.Day.GetHashCode()^entry.Month.GetHashCode(); 
    } 
} 

public class DateEntry : IComparable<DateEntry> 
{ 
    public int Day {get;set;} 
    public int Month {get;set;} 

    public int CompareTo(DateEntry entry) 
    { 
     var result = Month.CompareTo(entry.Month); 

     if(result == 0) 
     { 
      result = Day.CompareTo(entry.Day); 
     } 

     return result; 
    } 
} 

public class Calendar 
{ 
    public List<int> Months { get; set; } 
    public List<int> Days { get; set; } 
    public int Year { get; set; } 

    public Calendar(int year) 
    { 
     Months = new List<int>();  
     Days = new List<int>(); 
     Year = year; 
    } 

    public IEnumerable<DateEntry> GetDateEntries() 
    { 
     return from d in Days 
       from m in Months 
       select new DateEntry { Day = d, Month = m }; 
    } 
} 

그런 다음 당신이 할 수 있습니다

var items = years.SelectMany(y => y.GetDateEntries()).Distinct(new DateEntryComparer()).OrderBy(x => x); 
    items.Dump(); //Dump items to output in Linqpad. 

출력 : 나는 그것이 내가 생각했던 것보다 쉬울했다 * 알고 *

1 1 
6 1 
1 2 
6 2 
15 2 
6 4 
15 4