Искать два элемента одновременно в Swift? - PullRequest
0 голосов
/ 08 сентября 2018

У меня есть такая структура:

struct StructName {
    var name: String?
    var contents: [Content]?

}

Content выглядит так:

struct Content {
    var contentName: String?
}

Сейчас я просто ищу по names в моем массиве StructName

var array = [StructName]()

func searchBar(_ searchBar: UISearchBar, textDidChange searchText:String) {

    var filteredArray = array.filter { $0.name?.range(of: searchText, options: [.caseInsensitive]) != nil}

}

Как бы я подошел к этому, если я хочу искать внутри элементов в contents одновременно с name в StructName?

Если бы я структурировал это так:

let contentA = [Content(contentName: "Content_1"), Content(contentName: "Content_2")]
let contentB = [Content(contentName: "Content_1"), Content(contentName: "Content_2")]
array[0] = (StructName(name: "Name_1", contents: contentA))
array[1] = (StructName(name: "Name_2", contents: contentB))

И я написал «NC» в моем searchText, он должен вернуть все, так как есть «N» в «Name_1» и «Name_2» и есть «C» в «Content_1» и «Content_2».

Пример filteredArray:

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {

        filteredArray = array.filter{ elements in
            var result = false
            elements.contents.forEach{ content in
                if (content.contentName.lowercased().contains(searchText.lowercased()) ) {
                    result = true

                }
            }

            if (content.name?.lowercased().contains(searchText.lowercased()))!{
                result = true
            }

            return result
        }
  }

Обратите внимание, что поиск не выполняется одновременно, как я описал.

Ответы [ 2 ]

0 голосов
/ 09 сентября 2018

Ваше использование слова одновременный недостаточно ясно, чтобы описать, какого рода результаты поиска вы ожидаете.

Я полагаю,

если (и только если) name соответствует searchText или любому contentName в contents соответствует searchText, экземпляр StructName появляется в filteredArray.

( соответствует определяется как ваш name в вашем сообщении.)

Тогда вы можете написать что-то вроде этого:

var filteredArray = array.filter {
    $0.name?.range(of: searchText, options: .caseInsensitive) != nil
||  $0.contents?.contains {content in content.contentName?.range(of: searchText, options: .caseInsensitive) != nil} == true
}

Если это не то, что вам нужно, вам может потребоваться более точно указать условие поиска.


(Кстати, name или contents должен быть опциональным?)


(для вашего обновленного примера)

Похоже, вы хотите, чтобы поиск по каждому персонажу был вызван.

Используя немного модифицированный пример:

var array = [StructName]()
let contentA = [Content(contentName: "Content_1"), Content(contentName: "Content_2")]
let contentB = [Content(contentName: "Content_3"), Content(contentName: "Content_4")]
array.append(StructName(name: "Name_1", contents: contentA))
array.append(StructName(name: "Name_2", contents: contentB))

с некоторой справкой по отладке:

extension StructName: CustomStringConvertible {
    var description: String {
        return "\(name ?? ""):\(contents?.map{$0.contentName ?? ""}.joined(separator: ";") ?? "")"
    }
}
print(array) //->[Name_1:Content_1;Content_2, Name_2:Content_3;Content_4]

Вы можете написать что-то вроде этого:

func searchBar(_ searchBar: UISearchBar, textDidChange searchText:String) {
    let filteredArray = array.filter {element in
        !searchText.lowercased().contains {searchChar in
            !(element.name ?? "").lowercased().contains(searchChar)
                && !(element.contents ?? []).contains {content in (content.contentName ?? "").lowercased().contains(searchChar)}
        }
    }
    print(filteredArray)
}

Пример вывода:

searchBar(UISearchBar(), textDidChange: "NC") //->[Name_1:Content_1;Content_2, Name_2:Content_3;Content_4]
searchBar(UISearchBar(), textDidChange: "1")  //->[Name_1:Content_1;Content_2]
searchBar(UISearchBar(), textDidChange: "2")  //->[Name_1:Content_1;Content_2, Name_2:Content_3;Content_4]
searchBar(UISearchBar(), textDidChange: "12") //->[Name_1:Content_1;Content_2]

Хотя я не уверен, ожидаете ли вы этого, поскольку ваше описание еще недостаточно ясно.

0 голосов
/ 08 сентября 2018

Если вы хотите отфильтровать и найти StructNames, где элементы массива контента сравниваются с текстом панели поиска, при просмотре этого кода

struct Content {
    var contentValue: String
}

struct StructName{
    var name: String?
    var contents: [Content]?
}

var array = [ StructName(name: "test1", contents: [ Content(contentValue: "contentValue1"), Content(contentValue: "contentValue2"), Content(contentValue: "searchedText") ]) ]

let searchedText = "searchedText"

let filteredArray = array.filter{ structName in
    var result = false
    structName.contents?.forEach{ content in
        if (content.contentValue.lowercased().contains(searchedText.lowercased()) ) {
            result = true
        }
    }
    return result
}
...