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 theEquatable
protocol, compare e.g. Andrews's answer. - If the sequence elements are instances of a
NSObject
subclass
then you have to overrideisEqual:
, 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
Swift Generics and Protocols Not Working on Uikit [Possible Bug]
Swift 2: Multiline Mkpointannotation
Stanford Calculator App Keeps Crashing
Bulk Fix Hundreds of "#Selector Not Exposed to Objective-C" Errors in Xcode 9 or 9.1
Disable Email Detection in Swiftui's Text
Replacing Multiple Different Occurences with Multiple Different Replacements - Swift4.2
Stopping Timer at Defined Amount of Time in Swift
How to Unpack Multiple Levels of Nested JSON in Firebase Database
Avaudioplayer.Play() Works But Avaudioplayernode.Play() Fails
iOS 13 Swiftui: App Crashes Upon Launch on Real Device
How to Handle Unsafepointer<Unmanaged<Cfarray>>
Render Images on iOS 14 Widgets
Tests for Custom Uitableviewcell, Cellforrowatindexpath Crashes with Nil Outlets
Color Text of Status Bar in Xcode 6-B3 (Swift)
How to Simultaneously Satisfy Constraints Error Whats Causing This