2017-11-10 6 views
-2

역사적으로이 정렬 팩토리는 Invoice Item 객체의 배열을 하나의 차원으로 정렬 할 수있었습니다. 다양한 정렬 차원은 SortItem 개체의 속성으로 열거 형 "상태"내에 저장됩니다. 다음은 작동중인 구현입니다.NSArray를 2 차원으로 정렬 - Objective-C

+(NSArray *)SortInvoiceItems:(NSArray *)items forSort:(SortItem*)sortItem forSecondarySort:(SortItem*)secondarySortItem { 
    NSArray * primary = [items sortedArrayUsingComparator:^NSComparisonResult(id a, id b) { 
     InvoiceItems *iiA = (InvoiceItems *)a; 
     InvoiceItems *iiB = (InvoiceItems *)b; 
     switch(sortItem.state) { 
      case DateAscending: 
      case DateDescending: { 
       return (sortItem.state == DateAscending) ? [iiA.transactionDate compare:iiB.transactionDate] : [iiB.transactionDate compare:iiA.transactionDate]; 
      } 
      case SumDescending: 
      case SumAscending: { 
       return (sortItem.state == SumAscending) ? [iiA.netInvoiceAmount compare:iiB.netInvoiceAmount] : [iiB.netInvoiceAmount compare:iiA.netInvoiceAmount]; 
      } 
      case UnitPriceDescending: 
      case UnitPriceAscending: { 
       return (sortItem.state == UnitPriceAscending) ? [iiA.uomNetAmt compare:iiB.uomNetAmt] : [iiB.uomNetAmt compare:iiA.uomNetAmt]; 
      } 
      default: 
       return 0; 
     } 
    }]; 

    return primary; 
} 

사용되지 않는 메소드 서명에 secondarySort 매개 변수를 추가했습니다. 내 목표는이 2 차 특성에 따라 1 차 특성 값과 동일한 값을 갖는 Invoice Item 개체를 정렬하여이 2 차원 특성별로 정렬을 허용하는 것입니다.

예를 들어 두 항목의 .transactionDate가 같으면이 두 항목은 단가가 내림차순 인 두 번째 차원으로 추가로 정렬됩니다.

편집 : 아래에서 작업 했으므로이 코드를 작성하는 데 더 간결한 방법이 있습니까?

+(NSArray *)SortInvoiceItems:(NSArray *)items forSort:(SortItem*)sortItem forSecondarySort:(SortItem*)secondarySortItem { 

    NSSortDescriptor *primaryDescriptor; 
    NSSortDescriptor *secondaryDescriptor; 

    switch(sortItem.state) { 
     case DateAscending: 
      primaryDescriptor = [[NSSortDescriptor alloc] initWithKey:@"transactionDate" ascending:YES]; 
      break; 
     case DateDescending: 
      primaryDescriptor = [[NSSortDescriptor alloc] initWithKey:@"transactionDate" ascending:NO]; 
      break; 
     case SumAscending: 
      primaryDescriptor = [[NSSortDescriptor alloc] initWithKey:@"netInvoiceAmount" ascending:YES]; 
      break; 
     case SumDescending: 
      primaryDescriptor = [[NSSortDescriptor alloc] initWithKey:@"netInvoiceAmount" ascending:NO]; 
      break; 
     case UnitPriceAscending: 
      primaryDescriptor = [[NSSortDescriptor alloc] initWithKey:@"uomNetAmt" ascending:YES]; 
      break; 
     case UnitPriceDescending: 
      primaryDescriptor = [[NSSortDescriptor alloc] initWithKey:@"uomNetAmt" ascending:NO]; 
      break; 
     default: NSLog(@"invalid sort item"); 
    } 

    switch(secondarySortItem.state) { 
     case DateAscending: 
      secondaryDescriptor = [[NSSortDescriptor alloc] initWithKey:@"transactionDate" ascending:YES]; 
      break; 
     case DateDescending: 
      secondaryDescriptor = [[NSSortDescriptor alloc] initWithKey:@"transactionDate" ascending:NO]; 
      break; 
     case SumAscending: 
      secondaryDescriptor = [[NSSortDescriptor alloc] initWithKey:@"netInvoiceAmount" ascending:YES]; 
      break; 
     case SumDescending: 
      secondaryDescriptor = [[NSSortDescriptor alloc] initWithKey:@"netInvoiceAmount" ascending:NO]; 
      break; 
     case UnitPriceAscending: 
      secondaryDescriptor = [[NSSortDescriptor alloc] initWithKey:@"uomNetAmt" ascending:YES]; 
      break; 
     case UnitPriceDescending: 
      secondaryDescriptor = [[NSSortDescriptor alloc] initWithKey:@"uomNetAmt" ascending:NO]; 
      break; 
     default: NSLog(@"invalid sort item"); 
    } 

    NSArray *sortDescriptors = @[primaryDescriptor, secondaryDescriptor]; 
    return [items sortedArrayUsingDescriptors:sortDescriptors]; 
} 

SECOND 편집 : 여기에 리팩토링 :

+(NSArray *)SortInvoiceItems:(NSArray *)items forPrimarySort:(SortItem*)primary forSecondarySort:(SortItem*)secondary { 

    NSSortDescriptor *primaryDescriptor = [self GetDescriptorForSortItem:primary]; 
    NSSortDescriptor *secondaryDescriptor = [self GetDescriptorForSortItem:secondary]; 
    NSArray *sortDescriptors = @[primaryDescriptor, secondaryDescriptor]; 

    return [items sortedArrayUsingDescriptors:sortDescriptors]; 
} 

+(NSSortDescriptor *)GetDescriptorForSortItem:(SortItem*)sortItem { 
    switch(sortItem.state) { 
     case DateAscending: 
      return [[NSSortDescriptor alloc] initWithKey:kTransactionDateString ascending:YES]; 
     case DateDescending: 
      return [[NSSortDescriptor alloc] initWithKey:kTransactionDateString ascending:NO]; 
     case SumAscending: 
      return [[NSSortDescriptor alloc] initWithKey:kNetInvoiceAmount ascending:YES]; 
     case SumDescending: 
      return [[NSSortDescriptor alloc] initWithKey:kNetInvoiceAmount ascending:NO]; 
     case UnitPriceAscending: 
      return [[NSSortDescriptor alloc] initWithKey:kUOMNetAmount ascending:YES]; 
     case UnitPriceDescending: 
      return [[NSSortDescriptor alloc] initWithKey:kUOMNetAmount ascending:NO]; 
     default: 
      return [[NSSortDescriptor alloc] initWithKey:kTransactionDateString ascending:NO]; // default to date descending 
    } 
} 
+0

"어려운 이유"가 표시되지 않습니다. 왜 이것이 정확히 NSSortDescriptor가 해결하려고하는 문제가 아닌가? – matt

+0

몰랐어, 매트. 감사. 와우, 당신은 문자 그대로이 주제에 대한 책을 썼습니다. –

+0

좀 더 압축하면 switch 문을 전달 된 상태를 기반으로 설명자를 반환하기 위해 두 번 호출 할 수있는 별도의 메서드로 바꿔 넣습니다. –

답변

0

사용 NSArray-sortedArrayUsingDescriptors:이 문제를 해결합니다. 이 방법을 사용하면 NSSortDescriptor의 배열을 제공 할 수 있습니다. 두 번째 배열은 보조 정렬로 작동합니다 (세 번째 배열이 있으면 3 차 정렬 등).

-[NSSortDescriptor initWithKey:ascending:comparator:]을 사용하고 비교기 블록을 통과하여 NSSortDescriptor을 만들 수 있습니다.

0

여기에서 설명하는 등의 NSSortDescriptor를 사용하여 정렬을 구축 : https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/SortDescriptors/Articles/Creating.html

편집 : 귀하의 경우에는 당신이 정렬 디스크립터를 결정 state라는 SortItem 속성을 갖고 있기 때문에, 그것은 당신의 힘에 있기 때문에 그러나 state 유형을 구성하려면 원하는대로 상태 설명 부분을 작성하는 것이 좋습니다. 그렇게하면 정렬 할 시간이 없으므로 수행 할 작업이 없습니다. 상태 자체가 사용할 정렬 설명자를 제공하므로 SortInvoiceItems의 스위치를 제거 할 수 있습니다. 일반적으로 스위치는 나쁜 냄새로 볼 수 있습니다. 실제 객체가 무언가를 바꾸기보다는 무엇을해야하는지 알게해야합니다.

+0

'NSSortDescriptor'는 OP에서 이미 가지고있는 것과 같은 비교기 블록을 사용하여 초기화 할 수 있기 때문에 KVC조차 필요하지 않습니다. –

+0

좋아, 좋은 지적이야. – matt