Array Search Function Not Working in Swift

Search function for an Array

To find an index of an element when searching an array of type Any you need to cast the element to the proper type (String) before attempting for a comparison.

if let index = data.index(where:{ $0 as? String == "name" }) {
print(index)
}

iOS/Swift: why contains doesn't work to detect a substring in the .firstIndex function?

You use contains(_:), but if you look into the Apple Developer Documentation you see:

Returns a Boolean value indicating whether the sequence contains the given element.

So the whole string has to match if you use contains.

Content filter function not working... Can't find bug

string.rangeOfString does not do a prefix match. So if you search with "a", you don't have any people in your array with a name that is "a". If you want to do prefix match, try using String.hasPrefix (as described in https://developer.apple.com/library/mac/Documentation/General/Reference/SwiftStandardLibraryReference/index.html).

How to check if an element is in an array

Swift 2, 3, 4, 5:

let elements = [1, 2, 3, 4, 5]
if elements.contains(5) {
print("yes")
}

contains() is a protocol extension method of SequenceType (for sequences of Equatable elements) and not a global method as in
earlier releases.

Remarks:

  • This contains() method requires that the sequence elements
    adopt the Equatable protocol, compare e.g. Andrews's answer.
  • If the sequence elements are instances of a NSObject subclass
    then you have to override isEqual:, see NSObject subclass in Swift: hash vs hashValue, isEqual vs ==.
  • There is another – more general – contains() method which does not require the elements to be equatable and takes a predicate as an
    argument, see e.g. Shorthand to test if an object exists in an array for Swift?.

Swift older versions:

let elements = [1,2,3,4,5]
if contains(elements, 5) {
println("yes")
}

Swift Search Objects

You were so close! Breaking the code apart would have given better errors and you would have found it. ForEach requires the item to be hashable if self is used as the id. Using Track's id property in self probably cleared the bug. However, it took a little work to get there, so here is the refactored code.

Break out search filter into TrackModel so multiple field can be searched:

func search(_ query: String) -> Bool {
let searchable = [title, headline, description] + details

return searchable.filter({ $0.contains(query) }).count > 0
}

Next, add a calculated property in TrackView3 to encapsulate the list:

var filtered : [Track] {
if searchText.isEmpty {
return tracks
} else {
return tracks.filter({ $0.search(searchText) })
}
}

Now the ForEach doesn't have all that search stuff and its tidy form:

ForEach(filtered, id: \.id) { track in
TrackDetailView(tracks: track)
Divider()

}

Paul Hudson recently made a video with tips for better Swift Views. He covers encapsulating code in calculated properties. It makes for cleaner code and spares the coder from bugs in the declarative-tree (errors are not always helpful). 5 Steps to Better SwiftUI Views

IOS Swift Searching table from an Array

I do not understand why you iterate over the fruits using some kind of while loop. Instead I would propose you take advantage of a function like:

func filterFruits(searchText: String) -> [[String]] {
guard searchText != "" else {
return fruits
}
let needle = searchText.lowercased()
return fruits.filter {fruitObj in
return fruitObj.first!.lowercased().contains(needle)
}
}

That function returns all fruits that have a name containing the searchText.

filterFruits(searchText: "g") yields [["Orange", "Orange"]]

If you want to search through all attributes use something like:

func filterFruits(searchText: String) -> [[String]] {
guard searchText != "" else {
return fruits
}
let needle = searchText.lowercased()
return fruits.filter {fruitObj in
return fruitObj.contains { attribute in
attribute.lowercased().contains(needle)
}
}
}

filterFruits(searchText: "g") yields [["Apple", "Green"], ["Pear", "Green"], ["Orange", "Orange"]]

To get you on the right track for the future: you should really introduce a Fruit class which holds all relevant information of one specific fruit instance. Then you can use the first function and do something like fruitObj.matches(searchText) where you define a func inside the Fruit class which determines if the fruit matches the search.

Find an object in array?

FWIW, if you don't want to use custom function or extension, you can:

let array = [ .... ]
if let found = find(array.map({ $0.name }), "Foo") {
let obj = array[found]
}

This generates name array first, then find from it.

If you have huge array, you might want to do:

if let found = find(lazy(array).map({ $0.name }), "Foo") {
let obj = array[found]
}

or maybe:

if let found = find(lazy(array).map({ $0.name == "Foo" }), true) {
let obj = array[found]
}

UISearchBar search function does not work

Since the last update (which has played a major part for the solution) all I did was change the NSPredicate query from SELF CONTAINS[c] %@ to name CONTAINS[c] %@ and now when searching, it displays the correct matching object based on its name.



Related Topics



Leave a reply



Submit