2017-04-21 3 views
0

기본적으로 이것은이이 포트에 매핑 된 각 국가를 유지하는 배열 인 구조체 객체가 국가를 유지하고 포트문자열과 배열을 포함하는 구조체를 필터링하는 방법은 무엇입니까?

struct countryAndPorts { 
    var country: String? 
    var ports: [String]? 
} 

입니다. 필터링 된 배열은 국가 또는 포트별로 필터링 된 결과를 보유해야합니다.

var countryAndPortsArray = [countryAndPorts]() 
var filteredArray = [countryAndPorts]() 

현재 아래의 기능이 성공적으로 이제 내 문제는 내가 중 하나를 검색 키로 포트 또는 국가를 사용하여 필터링 된 결과를 얻기 위해 소원

func filteredContent(searchKey: String) { 
    filteredArray = countryAndPortsArray.flatMap{ $0 }.filter{$0.country?.lowercased().range(of: searchKey) != nil } 
} 

키 검색으로 국가를 사용하여 필터링 된 결과를 생성합니다. 가능한 한 최선을 다했지만 포트를 검색 키로 사용하여 바람직한 결과를 얻지 못하는 것 같습니다. 나의 현재 방법에 대한 개선은 많이 감사 할 것입니다. Objective-C의 응답도 환영합니다.

//Just incase it's of any use, these are my UITableView delegates 
extension SearchDealsViewController: UITableViewDelegate, UITableViewDataSource { 

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
    if let count = filteredArray[section].ports?.count { 
     return count 
    } 
    return 0 
} 

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) 

    if let port = filteredArray[indexPath.section].ports?[indexPath.row] { 
     cell.textLabel?.text = port 
    } 
    cell.textLabel?.font = UIFont.systemFont(ofSize: 10) 
    return cell 
} 

func numberOfSections(in tableView: UITableView) -> Int { 
    return filteredArray.count 
} 

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 
    portsFromTextField.text = filteredArray[indexPath.section].ports?[indexPath.row] 
} 

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { 
    let header = tableView.dequeueReusableCell(withIdentifier: "header") 
    let tapSectionHeaderGesture = UITapGestureRecognizer(target: self, action: #selector(getCountryText(sender:))) 
    tapSectionHeaderGesture.numberOfTouchesRequired = 1 
    tapSectionHeaderGesture.numberOfTapsRequired = 1 
    header?.addGestureRecognizer(tapSectionHeaderGesture) 

    if header != nil { 
     header?.textLabel?.textColor = THEME_COLOUR 
     header?.textLabel?.font = UIFont.boldSystemFont(ofSize: 12) 
     header?.textLabel?.text = filteredArray[section].country 
    } 

    return header 
} 

func getCountryText(sender: UITapGestureRecognizer) { 
    if let country = sender.view as? UITableViewCell { 
     portsFromTextField.text = country.textLabel?.text 
    } 
} 

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { 
    return 30 
} 

-------------------------------- UDPATE --------- ----------------------

"vlone"을 검색 문자열로 입력하는 순간 "vlone"과 "vlore"가 모두 반환됩니다. Vlone 및 블로 레는

Result yielded using vlone as search string

원하는 출력은 "vlone"를 포함하고 사용자가 쿼리를 특정 때문에 알바니아에서 다른 모든 포트를 떠나야한다 그러나 알바니아

모두 포트입니다.

두 번째 시나리오는 "바르셀로나"를 검색 키로 사용합니다. 스페인의 모든 포트를 포함하는 결과를 반환하지만 원하는 출력에는 바르셀로나 만 포함되어야합니다.

Results using barcelona as search key

+0

왜 매핑을위한 구조체를 정의합니까? 'var countriesAndPorts = [String : [String]]()'을 사용하고'let ports = countriesAndPorts [ "Spain"]'를 호출하여 국가의 항구를 얻으십시오. – NRitH

+0

@NRitH 구조가 사전보다 좋습니다. 다른 속성이있을 수 있습니다. 추가 할 수있는 논리가있을 수 있습니다. – rmaddy

+0

@NRitH 온라인 어딘가에서 보았지만 생각을 많이하지 않았습니다. 일반적으로 구조체를 사용하여 클래스가 아닌 약간 복잡한 데이터 구조를 만듭니다. –

답변

0

당신이 일치하는 국가 또는 포트가있는 모든 항목을 찾기 위해 배열을 필터링하려면, 당신은 할 수 있습니다 :

func filteredContent(searchKey: String) { 
    filteredArray = countryAndPortsArray.filter { 
     $0.country?.lowercased().range(of: searchKey) != nil || 
     !($0.ports?.filter { 
      $0.lowercased().range(of: searchKey) != nil 
     }.isEmpty ?? true) 
    } 
} 

이의이을 분해 보자. 최상위 수준에서는 을 countryAndPortsArray 배열로 호출합니다. 필터는 두 부분으로 구성됩니다. 1) 국가에 검색 텍스트가 있는지 확인하고 2) 포트에 검색 텍스트가 있는지 확인합니다. 당신이 이미 가지고 있던 일부입니다

$0.country?.lowercased().range(of: searchKey) != nil 

:

첫 번째 검사가 이루어집니다. 필터는 어느 포트가 검색 텍스트가 포함되어 있는지 사용되고, 이후 ports

!($0.ports?.filter { 
    $0.lowercased().range(of: searchKey) != nil 
}.isEmpty ?? true) 

배열이다

번째 체크

이 이루어집니다. isEmpty은 일치하는 포트의 결과 필터 목록이 비어 있는지 확인합니다. ports은 선택 사항이므로 ?? true을 사용하면 일치하는 포트 목록이 비어있는 것처럼 작동합니다. !은 결과를 무효화합니다. 일치하는 목록이 비어 있거나 portsnil 인 경우 true은 일치 포트가 없음을 나타내는 false으로 무효화됩니다.

두 개의 검사는 표준 논리 "or"연산자 ||을 사용하여 결합됩니다. 즉, 최상위 필터가 해당 레코드와 일치하도록하려면 두 검사 중 하나만 참이어야합니다.

+0

@maddy Ahh 생명의 은인, 완벽하게 작동합니다. 고통이되는 것을 의미하지는 말고, 몇 분만 기다려 주시면 솔루션을 무너 뜨릴 수 있습니다. 아직도 이러한 고차원 함수를 일반적으로 사용하고 있습니다. 감사합니다 –

+0

설명을 사용하여 답변을 업데이트했습니다. 그게 더 명확 해? – rmaddy

+0

감사합니다. 훨씬 더 명확합니다. 한 가지 더, 지금 "런던"을 검색하면 영국과 남아프리카의 모든 항구가 생겨납니다 (SA에서는 "이스트 런던"이라는 항구가있는 것 같습니다). "런던"과 일치하는 포트만 가져올 수 있습니까? –

관련 문제