2013-06-20 1 views
1

항목 유형을 번갈아 목록을 만들어야합니다. 내 원래 목록에서항목 유형에 따라 목록 항목을 대체하는 알고리즘 만들기

, 나는이 있습니다

그룹 - 유형
그룹 1 - 1
그룹 2 - 2
그룹 3 - 1
그룹 4 - 1
Group5 - 1
Group6 - 2
그룹 7-3

그리고이 방법으로 항목을 다시 구성하고 싶습니다.

012 3,516,

그룹 1 - 1
그룹 2 - 2
Group7 - 3
그룹 3 - 1
Group6 - 2
Group7 - 3
그룹 4 - 1
그룹 2 - 2
Group7 - 3
Group5 - 1
그룹 6 - 2
그룹 7 - 3

이해할 수 있습니까? 더 많은 항목이있는 유형의 개수에 따라 다른 항목과 번갈아 가며해야합니다.

이 알고리즘은 n 유형을 englobe해야합니다.

나는 조금 잃어 버렸습니다. 누구든지 나를 도울 수 있습니까? 어떤 알고리즘을 사용합니까?

나는이 수행 될 수 있습니다 얼마나 모르겠지만, 기능적이어야한다
+0

유형에 따라 목록 항목을 그룹화하여 각 유형별로 하나의 목록을 만들 수 있다고 생각합니다. 그런 다음 필요할 때마다 배치하여 반복합니다. –

+1

나는 조금 잃어 버렸다. 당신이하려고하는 것을 더 잘 설명해야합니다. –

답변

0

을 이해 바랍니다 extension method는 의미는 다음과 같이 호출 할 수 있습니다 : 다음 작품 같은

var input = new[] 
{ 
    new { Group = "Group1", Type = 1 }, 
    new { Group = "Group2", Type = 2 }, 
    new { Group = "Group3", Type = 1 }, 
    new { Group = "Group4", Type = 1 }, 
    new { Group = "Group5", Type = 1 }, 
    new { Group = "Group6", Type = 2 }, 
    new { Group = "Group7", Type = 3 }, 
}; 

var results = input.AlternateGroups(x => x.Type); 
// Group1 1 
// Group2 2 
// Group7 3 
// Group3 1 
// Group6 2 
// Group7 3 
// Group4 1 
// Group2 2 
// Group7 3 
// Group5 1 
// Group6 2 
// Group7 3 
1

:

당신이 그룹의 요소를 넣어하는 배열의 배열을 만들어 배열의 [I] [J], 당신 때문에 그룹 1, 그룹 3, 그룹 4, Group5

배열 [1] : 그룹 2, 그룹 2

배열 [2] : 그룹 3

어레이 [0]과 같은 있어야 각 배열에 대해 방금 추가 한 요소를 가리키는 인덱스를 저장하십시오.

마지막으로 배열 배열과 "열"사이를 순환하여 하위 배열 끝에 도달하면 인덱스 다시 시작을 0으로 만듭니다. 아름다운 것은 아니지만 잘 작동해야합니다.

public static IEnumerable<TSource> AlternateGroups<TSource, TKey>(this IEnumerable<TSource> list, Func<TSource, TKey> keySelector) 
{ 
    var groups = list.GroupBy(keySelector).OrderByDescending(g => g.Count()); 
    var largestGroup = groups.First(); 
    var arrays = groups.Skip(1).Select(g => g.ToArray()); 
    var index = new int[arrays.Count()]; 
    foreach(var item in largestGroup) 
    { 
     yield return item; 
     var i = 0; 
     foreach(var a in arrays) 
     { 
      yield return a[index[i++]++ % a.Length]; 
     } 
    } 
} 

이가로 작성 : 나는 확신하지만 내 영어 죄송합니다

, 나는이 개선 될 수있다, 다음이에서 내 주먹 찌르기의 당신이 :)

0

뭔가, 내가 더 우아한 솔루션이 확신하지만.

편집 : 의견에서 지적

, 나는 요소가 가장 긴 그룹화 목록의 길이를 만들기 위해 짧은 목록에서 다시 사용하는 것을 몰랐어요. 여기에 수정 된 버전이 있습니다.

void Main() 
{ 
    var list = new List<Group>{ 
     new Group { Name = "Group1", Type = 1 }, 
     new Group { Name = "Group2", Type = 2 }, 
     new Group { Name = "Group3", Type = 1 }, 
     new Group { Name = "Group4", Type = 1 }, 
     new Group { Name = "Group5", Type = 1 }, 
     new Group { Name = "Group6", Type = 2 }, 
     new Group { Name = "Group7", Type = 3 } 
    }; 

    var groups = list.GroupBy(g => g.Type).ToList();  
    var groupCounts = groups.Select(g => g.Count()).ToArray(); 
    var biggestGroup = groupCounts.Max(); 

    var newList = new List<Group>(); 
    for (int i = 0; i < biggestGroup; i++) 
    { 
     for (int j = 0; j < groups.Count; j++) 
     { 
      var element = groups[j].ElementAt(i % groupCounts[j]); 
      newList.Add(element); 
     } 
    } 

    // newList contains the ordered items 
} 

public class Group 
{ 
    public string Name { get;set; } 

    public int Type { get;set; } 
} 

출력

Group1 1 
Group2 2 
Group7 3 
Group3 1 
Group6 2 
Group7 3 
Group4 1 
Group2 2 
Group7 3 
Group5 1 
Group6 2 
Group7 3 

당신은 IEnumerable<Group>yield return 항목을 반환하는 확장 메서드에이를 만들 수 있습니다.

+0

제대로 작동하려면 입력 목록에 여분의 2와 3이 있어야합니다. 질문에 입력 된 내용이 없으므로 일부 요소를 다시 사용해야합니다. – Dukeling

+0

@Dukeling 필요가 없지만 각 그룹에 남아있는 나머지 값을 쓰게됩니다. 그룹의 가치를 되풀이 할 것으로 예상되는 것을 나는 깨닫지 못했다. –

+0

@Dukeling 업데이트 됨. p.su.w.g의 대답과 같은 일을하는 다른 코드 http://stackoverflow.com/a/17225047/1831 –

관련 문제