Swift: Can not use array filter in if let statement condition
You can make this work by putting parentheses around the closure that you're passing to filter
:
if let selected = users.filter({$0.characters.count == 2}).first {
print(selected)
}
That is the right way to do it. The trailing closure syntax doesn't work very well sometimes on lines with extra elements. You could also put parentheses around the whole statement:
if let selected = (users.filter {$0.characters.count == 2}.first) {
print(selected)
}
Swift is just having trouble parsing your statement. The parentheses give it help in how to parse the line. You should prefer the first way since the closure is indeed a parameter of filter
, so enclosing it in parentheses makes it clear to Swift that you are passing it to filter
.
How does filter know what the condition is if it is supposed to just return a boolean value?
filter
iterates over all elements of the Array
it is called on, executes the same closure for each element and returns a new array, which only contains the elements, for which the closure returned true
.
How does this code know to get only the booking values if this: $0.startdate!.toString(dateFormat: "yyyy-MM-dd").contains(selectedDate) is just returning a boolean value? It must also return an array right? (or a copy / reference of one)
As explained above, the condition in that closure is executed for each element of bookings
and filter
returns a new Array
, which contains only the elements for which the closure returned true
.
Your second expression with the nested ternary expression is actually equivalent to your first expression without the nested ternary expression. If you look at it more closely,$0.startdate!.toString(dateFormat: "yyyy-MM-dd").contains(selectedDate) ? true : !$0.startdate!.toString(dateFormat: "yyyy-MM-dd").contains(selectedDate)
, the expression after the :
is simply the negated version of the condition of your ternary expression. So basically, this means a ? true : !a
, which is equivalent to a
itself.
If you want to achieve
So based on that, I wanted to add more functionality so that if the user selected a date where there were no matches, all of the bookings are displayed.
, I would suggest saving the result of your original filter
into a local variable, then checking whether this array is empty, if not, call ForEach
on the filtered array, otherwise call it on bookings
.
let bookingsForSelectedDate = self.bookings.filter { self.selectedDate.isEmpty ? true : $0.startdate!.toString(dateFormat: "yyyy-MM-dd").contains(selectedDate) }
let matchingOrAllBookings = !bookingsForSelectedDate.isEmpty ? bookingsForSelectedDate : self.bookings
ForEach(matchingOrAllBookings, id: \.self) { booking in
NavigationLink(destination: BookingDetail(theBooking: booking)) {
HStack {
...
}}
Swift filter array by condition
It should be simple until unless you don't have some other requirement.
cats.filter { $0.id == 7 }
And to skip optional values you can use compactMap
e.g
let array: [Cat] = [
Cat(id: 7, name: "CatA"),
Cat(id: nil, name: "CatB"),
Cat(id: 1, name: "CatC"),
Cat(id: 7, name: "CatD"),
Cat(id: 7, name: "CatE"),
Cat(id: 2, name: "CatF"),
Cat(id: nil, name: "CatG"),
]
print(array.compactMap { value -> Cat? in
guard let id = value.id, id > 2 else { return nil }
return value
})
Why is result of filter with count not usable directly as conditional in Swift 3
Swift has trouble parsing anonymous closure in the context of an if
logical expression. You can work around this issue by parenthesizing the count
expression:
if (myStructArray.filter{$0.isLocked == true}.count) < 4 {
// ^ ^
print("Fewer than 4 locked")
}
or
if (myStructArray.filter{$0.isLocked == true}.count < 4) {
// ^ ^
print("Fewer than 4 locked")
}
or
if myStructArray.filter({$0.isLocked == true}).count < 4 {
// ^ ^
print("Fewer than 4 locked")
}
Swift filter with condition
Append
&& IoC.filterDataService.autoTransmision ? $0.car.gearingType == .automatic : true
to your initial conditions
Get output out of filter when there are no results
You need to check if your filtered array in if
is empty:
let filteredArray = array.filter({...})
if !filteredArray.isEmpty {
ForEach(filteredArray) { item in
// do things if found
}
} else {
Text("No results at all")
}
Filter by multiple array conditions
Forget about the filter for a moment. Think how you would check if a car's color is a value in an array.
let colors = [ "Green", "Blue" ]
// or let colors: Set = [ "Green", "Blue" ]
if colors.contains(someCar.color) {
}
Simple enough. Now use that same simple expression in the filter.
let filterdObject = cars.filter { $0.model == currModel || colors.contains($0.color) }
Related Topics
Parse.Com Pfgeopoint.Geopointforcurrentlocationinbackground Not Doing Anything
How to Rotate an Object Around Only One Axis in Realitykit
Referencing Self in Super.Init
Cast to Different C Struct Unsafe Pointer in Swift
Tvos Textfield Transparent Background
How, Exactly, Do I Render Metal on a Background Thread
In Swift, How to Wait Until a Server Response Is Received Before I Proceed
Does Swift Have Short-Circuiting Higher-Order Functions Like Any or All
Apple Push Notifications Without Developer Account
Observe Progress of Data Download in Swift
Usage of Withmemoryrebound with Apples Swift 3 Beta 6
Extending Typed Array by Conforming to a Protocol in Swift 2
Images Inaccessible from Asset Catalog in a Swiftui Framework
Hittest Prints Ar Entity Name Even When I am Not Tapping on It
How to Masking the Last Number in Swift
Why Do We Need to Set Delegate to Self? Why Isn't It Defaulted by the Compiler
Cannot Call Value of Non-Function Type 'Nshttpurlresponse' Alamofire Objectmapper