2017-11-27 1 views
0

다른 속성 값으로 사용자 지정 구조 배열을 쉽게 정렬하려고합니다.Swift에서 다른 속성 값으로 사용자 정의 개체 정렬

struct Customer: Comparable, Equatable { 
    var name: String 
    var isActive: Bool 
    var outstandingAmount: Int 
    var customerGroup: String 
} 

var customerlist: [Customer] // This is downloaded from our backend. 

사용자가 다양한 아이콘을 선택하면 모든 필드 값으로 UI의 고객 목록 배열을 정렬 할 수 있기를 원합니다.

switch 문을 사용하여 정렬하는 몇 가지 방법을 시도했지만 - 올바른 방법은 Sort Descriptors (Objective-C 기반으로 표시되며 배열을 변환해야 함)를 사용한다고 말합니다. NSArray.) 네이티브 스위프트 구조체를 사용하여이 방법을 시도하면 오류가 계속 발생합니다.

사용자가 Swift를 사용하여 위의 배열을 정렬 할 수있게하는 가장 좋은 방법은 무엇입니까?

예 : 아래가 매우 장황하게 보인다!

func sortCustomers(sortField:ColumnOrder, targetArray:[Customer]) -> [Customer] { //Column Order is the enum where I have specified the different possible sort orders 
     var result = [Customer]() 
    switch sortField { 
     case .name: 
      result = targetArray.sorted(by: { (cust0: Customer, cust1: Customer) -> Bool in 
       return cust0.name > cust1.name 
      }) 
     case .isActive: 
      result = targetArray.sorted(by: { (cust0: Customer, cust1: Customer) -> Bool in 
       return cust0.isActive > cust1.isActive 
      }) 
     case .outstandingAmount: 
      result = targetArray.sorted(by: { (cust0: Customer, cust1: Customer) -> Bool in 
       return cust0.outstandingAmount > cust1.outstandingAmount 
      }) 
     case .customerGroup: 
      result = targetArray.sorted(by: { (cust0: Customer, cust1: Customer) -> Bool in 
       return cust0.customerGroup > cust1.customerGroup 
      }) 
    } 
    return result 
} 
+0

당신은 (그들에게 이름을주는 대신 위치 인수를 사용하여 클로저를 단순화 할 수 있습니다 예를 들어, 경우 1 :.'targetArray.sorted을 {$ 0.name> $ 0.name}') –

+0

Sort Descriptors가 올바른 접근 방식이라고 생각합니다. -하지만 작동하지 않는 것 같습니다 –

답변

1

나는, 사용 KeyPaths와 함께 갈 것입니다 무엇 :

func sortCustomers<T: Comparable>(customers: [Customer], with itemPath: KeyPath<Customer, T>) -> [Customer] { 
    return customers.sorted() { 
     $0[keyPath: itemPath] < $1[keyPath: itemPath] 
    } 
} 

이러한 접근 방식은 전혀 열거의 필요성을 방지하고, 그냥

let testData = [Customer(name: "aaaa", isActive: false, outstandingAmount: 1, customerGroup: "aaa"), 
       Customer(name: "bbbb", isActive: true, outstandingAmount: 2, customerGroup: "bbb")]; 

let testResultsWithName = sortCustomers(customers: testData, with: \Customer.name) 
let testResultsWithActive = sortCustomers(customers: testData, with: \Customer.isActive) 
// etc 

공지 사항을 수행 할 수 있습니다 그 ><으로 바꿨습니다. 즉 등

는 또한, 당신이 BOOL이 비교 될 때까지 확장을 추가해야합니다, "1"전에 "2", 기본 기대하고 "A"전에 "B"가 발생합니다 :

extension Bool: Comparable { 
    public static func <(lhs: Bool, rhs: Bool) -> Bool { 
     return lhs == rhs || (lhs == false && rhs == true) 
    } 
} 

이 접근 방식을 완성하기 위해, 당신은 또한 비교 함수에 전달할 수 있습니다

func sortCustomers<T: Comparable>(customers: [Customer], comparing itemPath: KeyPath<Customer, T>, using comparitor: (T, T) -> Bool) -> [Customer] { 
    return customers.sorted() { 
     comparitor($0[keyPath: itemPath], $1[keyPath: itemPath]) 
    } 
} 
let testResults = sortCustomers(customers: testData, comparing: \Customer.name, using: <) 

이 방법을 사용하면 일반적인 비교 연산자를 사용할 수 있습니다 : (<, < =,>,> =)뿐만 아니라 폐쇄 맞춤 정렬이 필요한 경우

+0

그건 꽤 예뻐요 – vadian

+0

맞죠? KPs는 대단합니다! – PeejWeej

+0

정말 멋지지만 NSSortDescriptors가 올바른 접근 방식이라고 생각합니다. 오름차순 또는 객체 배열의 내림차순을 유연하게 적용 할 수 있기 때문입니다.- 그냥 작동하지 않는 것 같습니다 –

0

나는 더 멋진 솔루션을 만들기 위해 재구성했다. 주문 폐쇄를 반환하는 ColumnOrder에 속성을 추가했습니다. 여기

struct Customer { 
    var name: String 
    var isActive: Bool 
    var outstandingAmount: Int 
    var customerGroup: String 
} 

enum ColumnOrder { 
    case name 
    case isActive 
    case outstandingAmount 
    case customerGroup 

    var ordering: (Customer, Customer) -> Bool { 
     switch self { 
     case .name:    return { $0.name > $1.name } 
     case .isActive:   return { $0.isActive && !$1.isActive } 
     case .outstandingAmount: return { $0.outstandingAmount > $1.outstandingAmount} 
     case .customerGroup:  return { $0.customerGroup > $1.customerGroup } 
     } 
    } 
} 

그것이 사용되는 방법입니다

let sortedCustomers = customers.sorted(by: ColumnOrder.name.ordering) 

다음, 나는 배열에서 호출 잘 보이게하기 위해 Sequence을 확장했다.

extension Sequence where Element == Customer { 
    func sorted(by columnOrder: ColumnOrder) -> [Element] { 
     return sorted(by: columnOrder.ordering) 
    } 
} 

최종 결과 :

let sortedCustomers = customers.sorted(by: .name) 
관련 문제