2013-05-30 2 views
4

나는 LINQ 등에서 할 수있는 달콤한 방법이 있는지 궁금 합니다만, X 부분에 걸쳐 알파벳의 글자를 가장 균등하게 배분하려고합니다. 정수> 0 & & < = 26 예를 들어 여기에는 몇 가지 가능한 출력이있을 수 있습니다.알파벳 순서로 알파벳을 가장 균등하게 배분합니다.

  • X = 1 : 26
  • 1 개 파티션 X = 2 : 13
  • 2 개 파티션 X = 3 : 2 개의 9 파티션 8
  • 등의 파티션 ....

궁극적으로 나는 하나 이상의 파티션을 갖지 않는 파티션을 갖고 싶지 않고 파티션 크기 차이의 범위가 작다는 것을 가장 균등하게 배분할 것을 목표로 삼고 있습니다. 가능한 한.

내가 orginally 히 노력 코드입니다 :

char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray(); 
int pieces = (int)Math.Round((double)alphabet.Count()/numberOfParts); 
for (int i = 0; i < numberOfParts.Count; ++i) { 
    char[] subset = i == numberOfParts.Count - 1 ? alphabet.Skip(i * pieces).ToArray() 
        : alphabet.Skip(i * pieces).Take(pieces).ToArray(); 
... // more code following 

이 처음에는 잘 작동하는 듯하지만 X는 내가 갖는이 논리를 바탕으로 10 때 문제가 있음을 테스트 실현 3의 8 개의 그룹과 2의 1 개의 그룹, 제 10의 그룹을 남겨둔다. 0은 나쁘지 않다.

이 경우 10에 가장 이상적인 분포는 3과 4 그룹으로 구성된 6 개의 그룹입니다. 어떻게 구현 될지 생각해보십시오.

+0

귀하의 질문은 매우 소리 구체적이고 명확하지 않은 경우 여기에서 달성하려는 내용을 자세히 설명해 주실 수 있습니까? 이 교과 과정도 있습니까? 그렇다면 문제는 아니지만 대답에 영향을 미칠 수 있으므로 알려주십시오. –

+0

다른 숙제가 아닙니다. 시작 문자를 기반으로 다른 위치에 메시지를 배포하려고합니다. –

+0

공정한 정도 - 이유에 대해 자세히 설명해 주시겠습니까? 나는 영리한 대답과 좋은 대답이 여기에 있다는 느낌을 가지고 있습니다! –

답변

3

일반적으로 논리를 구현하는 가장 쉬운 방법은 모듈러스 연산자 %를 사용하는 것입니다. 이 연산자에 익숙해 지십시오. 도움이되는 상황에 매우 유용합니다. 또는 배열을 사용하여 문자의 분포를 할 수있는 실제 코드를 작성하는 방법에는 여러가지가있다 당신이 등 좋겠지 만,이 짧은 표현이 당신에게 아이디어를 줄 것이다으로하지 :

"ABCDEFGHIJKLMNOPQRSTUVWXYZ".IndexOf(letter) % partitionCount 

이 표현은 제로를 제공합니다 대문자를 배치 할 파티션의 인덱스. 문자열은 편의상 표시되었지만 배열이나 알파벳을 나타내는 다른 방법 일 수 있습니다. 위와 유사한 논리를 사용하여 각 문자를 어디에 배치할지 선택할 수 있습니다. 루프 내에서, 메서드 내에서 로직을 넣을 위치는 당신에게 달려 있습니다.

모듈러 산술에 관해서는 아무것도 없습니다. 사용할 수있는 숫자 집합의 끝에 도달하면 방금 "랩 어라운드"합니다. 우리가이 모든 것을 경험 한 간단한 맥락은 분열에 있습니다. % 연산자는 본질적으로 단지 나눗셈 나머지를 제공합니다. % 연산자가 수행하는 작업을 이해 했으므로 모든 언어에서 동일한 작업을 수행 할 수있는 자신 만의 코드를 쉽게 작성할 수 있습니다.

모두 함께이 퍼팅,이 같은 유틸리티, 클래스 또는 확장 방법을 쓸 수 - 나머지를 계산 %를 기록하고 간단한 정수 나누기 그것을 삭제 : 내가 무슨 짓을

/// <summary> 
/// Returns partition sized which are as close as possible to equal while using the indicated total size available, with any extra distributed to the front 
/// </summary> 
/// <param name="totalSize">The total number of elements to partition</param> 
/// <param name="partitionCount">The number of partitions to size</param> 
/// <param name="remainderAtFront">If true, any remainder will be distributed linearly starting at the beginning; if false, backwards from the end</param> 
/// <returns>An int[] containing the partition sizes</returns> 
public static int[] GetEqualizedPartitionSizes(int totalSize, int partitionCount, bool remainderAtFront = true) 
{ 
    if (totalSize < 1) 
     throw new ArgumentException("Cannot partition a non-positive number (" + totalSize + ")"); 
    else if (partitionCount < 1) 
     throw new ArgumentException("Invalid partition count (" + partitionCount + ")"); 
    else if (totalSize < partitionCount) 
     throw new ArgumentException("Cannot partition " + totalSize + " elements into " + partitionCount + " partitions"); 

    int[] partitionSizes = new int[partitionCount]; 
    int basePartitionSize = totalSize/partitionCount; 
    int remainder = totalSize % partitionCount; 
    int remainderPartitionSize = basePartitionSize + 1; 
    int x; 

    if (remainderAtFront) 
    { 
     for (x = 0; x < remainder; x++) 
      partitionSizes[x] = remainderPartitionSize; 

     for (x = remainder; x < partitionCount; x++) 
      partitionSizes[x] = basePartitionSize; 
    } 
    else 
    { 
     for (x = 0; x < partitionCount - remainder; x++) 
      partitionSizes[x] = basePartitionSize; 

     for (x = partitionCount - remainder; x < partitionCount; x++) 
      partitionSizes[x] = remainderPartitionSize; 
    } 

    return partitionSizes; 
} 
+0

주, 즉 그것은,이 응답 풋 'A'를 약자로 및 'B'그룹을 하나 이상 가지고 있으면 별도의 그룹에 있습니다. 원래 질문 및 기타 답변은 페이지 매김과 같이 연속적인 인덱스를 분할하려고 시도합니다. –

+0

@Mark Hurd : 고맙습니다. 답변을 업데이트했습니다. – Iucounu

1

하나의 응용 프로그램에서 내가 그룹에 물건을 배포했다 이것은 당신에게 당신이 예상 정확한 결과를 제공하지 않습니다이

var numberOfPartitions = GetNumberOfPartitions(); 
var numberOfElements = GetNumberOfElements(); 

while (alphabet.Any()) 
{ 
    var elementsInCurrentPartition = Math.Ceil((double)numberOfPartitions/numberOfElements) 

    for (int i = 0; i < elementsInCurrentPartition; i++) 
    { 
      //fill your partition one element at a time and remove the element from the alphabet 
      numberOfElements--; 
    } 
    numberOfPartitions--; 
} 

같은 (10 개 파티션 즉, 이상적인 결과)했지만 그것은 아주 가까이 있습니다.

p.s.이것은 테스트되지 않은 상태입니다 :)

내가 지금 테스트 한 의사 코드 알고리즘
1

:

Double count = alphabet.Count() 
Double exact = count/numberOfParts 
Double last = 0.0 
Do Until last >= count 
    Double next = last + exact 
    ranges.Add alphabet, from:=Round(last), to:=Round(next) 
    last = next 
Loop 

ranges.Add

Here :-) 빈 범위를 무시할 수는이 알고리즘의 LinqPad VB.NET 구현입니다 .

그래서이의 Linq에 버전이

Double count = alphabet.Count(); 
Double exact = count/numberOfParts; 

var partitions = Enumerable.Range(0, numberOfParts + 1).Select(n => Round((Double)n * exact)); 

Here 같은 것이 LINQ 쿼리를 사용하여 LinqPad VB.NET 구현입니다.

2

각 문자에 라운드 로빈 배포를 수행하는 것이 가장 간단한 방법이라고 생각합니다. 알파벳의 각 문자를 순환하여 추가 한 다음 반복합니다. 아이템을 넣을 글자를 결정한 실행 횟수를 가졌고, 26보다 큰 경우 0으로 다시 설정하십시오!

+0

극단적 인 개념 단순화를 위해 선정되었습니다. 이같은 일과를 통해 일반적으로 문제가되지 않으며, 일반적으로 KISS 접근법에 대해 언급해야 할 것이 많습니다. – Iucounu

0

은 (포맷 죄송합니다, 모바일)

가 이

먼저 배치 방법과 같이해야합니다 :

다음
public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> source, int groupSize) 
{ 
    var tempSource = source.Select(n => n); 
    while (tempSource.Any()) 
    { 
     yield return tempSource.Take(groupSize); 
     tempSource = tempSource.Skip(groupSize); 
    } 
} 

, 단지 다음과 같이 호출을 :

var result = alphabet.Batch((int)Math.Ceiling(x/26.0)); 
관련 문제