Find multiple elements that are equal to a condition in array? - ios

I am a new to SwiftUI, so I apologise if this a dumb question but I came upon a problem that I cant find a solution to.
I am searching something similar to this code below, but instead of finding the first element I would like to retrieve all elements that have the status == 0.
if let new = array.first(where: {$0.status == 0}) {
// do something with foo
} else {
// item could not be found
}

Swift collections have a filter method which allows you to select all elements that match a given condition. You already have a matching condition, so to adapt your example text you'd write:
let newItems = array.filter { $0.status == 0 }

Related

Remove a particular value from array instead of remove using index path

I am working in array handling , the overall working of the application is the user can select the number of number of songs that has to be added to a particular playlist. I have used Tableview to list the songs when the user click the tableview cell have added .checkmark when already checkmark found I will remove .checkmark, similarly when the user select the song I have kept a array to save the track id of that particular song .
"SongIDArray" is the array used to save. When the user deselect the song I have to delete the particular songs "track id". but in array it has remove(at: index) I cannot delete it through index. please help me
for example :** my array is**
songIDArray = [25,45,69,78,63]
I need to remove 78 from the index without knowing the index path.
You can use filter to remove values from an array:
let newArray = [25, 45, 69, 78, 63].filter { $0 != 78 }
removeAll is the command for conditionally removing.
var array = [25,45,69,78,63]
array.removeAll{$0 == 78}
print(array)
//[25, 45, 69, 63]
You have a few options here, whichever is best suited to your exact use-case!
Remove by filtering
The filter function passes each element in the array to the block of code you provide and removes all items you return false for. This is useful for performing a simple filter, but if you also need the index of the removed item (For example to reload a table view index path) it's not very useful.
songIDArray = songIDArray.filter({ id in
return id != 78
})
Remove by index
First get the index to remove at, you can do this in various ways depending on the type of items you have in your array. If they conform to Equatable (Integers do) you can use
if let removalIndex = songIDArray.firstIndex(of: 78) {
songIDArray.remove(at: removalIndex)
}
If you don't have an array of Equatable elements, then you can instead use index(where:) which returns the first index for which you return true from the provided closure:
if let removalIndex = songIDArray.index(where: { id in
return id == 78
}) {
songIDArray.remove(at: removalIndex)
}
This method is useful if you also need to do something else with the index, like reload a UITableViewCell at a specific index path to reflect your change e.t.c.
Remove All
In swift 4.2 there is also a removeAll(where:) function which works similar to filter but doesn't return a new array:
songIDArray.removeAll(where: { id in
return id == 78
})

Checking if array is nil or not [duplicate]

This question already has answers here:
Check if optional array is empty
(8 answers)
Closed 4 years ago.
I have a array of my custom model, and I want to check if it is not nil and its size is greater then 0.
Following is my array with custom object
var listCountries : [Countries]? = nil
now In viewDIdLoad I want to make a check on it. I am new to Swift. I have good experience in working in Java.
I have read out Optional values concept and guard, if let statements. But I am unable to understand how efficiently they may be used. I have read too much SO questions but failed to figure out.
for example , if I want to check the upper given array in java I have only to do
if(listCountries != null && listCountries.size()>0){
//DO something
}
So to summarize my question:
How to make the upper given(Java code) check in to swift 4.? What is more smooth and reliable way.
What is a use of if let , guard, guard let statements. if I declare a variable (array, string) as optional I have to bear optional check like force wrapping each and every place. This is for me so making too much confusion.
Please help. I know this question has been asked in different ways. But this has some different context.
Just use ??.
if !(listCountries ?? []).isEmpty {
However, since you want to probably use listCountries in the if block, you should unwrap
if let listCountries = self.listCountries, !listCountries.isEmpty {
Ideally, if nil and empty means the same to you, don't even use an optional:
var listCountries: [Countries] = []
I would do it something like...
if let list = listCountries, !list.isEmpty { // Can also use list.count > 0
// do something
}
Even though you are not using the list inside the braces you are still using the list in the condition.
Or, like Sulthan said... make it non-optional to begin with if it makes no difference.
Obviously, I would assume that you are able to recognize the difference between nil array and empty array.
So, if we tried to implement a literal translation to your question:
I want to check if it is not nil and its size is greater then 0
For the first condition:
// "I want to check if it is not nil":
if let unwrappedList = listCountries {
// ...
}
and for the second condition:
// "I want to check if it is not nil":
if let unwrappedList = listCountries {
// "and its size is greater then 0":
if !unwrappedList.isEmpty {
// ...
}
}
However, you could combine both of the conditions by using the comma to achieve the multi-clause condition:
// I want to check if it is not nil and its size is greater then 0
if let unwrappedList = listCountries, !unwrappedList.isEmpty {
// ...
}
Or by using guard statement:
// I want to check if it is not nil and its size is greater then 0
guard let unwrappedList = listCountries, !unwrappedList.isEmpty else {
return
}
if let list = listCountries {
if(!list.isEmpty && list.count > 0) {
//value
}
}

index(where:) method in swift is producing the wrong index

I have received an array index out of range error. I have two arrays cardsCurrentlyInPlay and currentCardsSelected. Every card that is in this game has a unique ID. I am attempting to find find the index of the card in cardsCurrentlyInPlay whose cardID matches the cardID of the card in currentCardsSelected. I am doing this by using the index(where:) method that takes a closure. My closure just checks if the IDs match, they obviously match because I am using the ! to unwrap them and the app does not crash there. It seems as though the index(where:) method is returning the wrong index. I have looked at this for hours and I do not understand whats going on.
Heres the code:
let indexOfFirstCard = cardsCurrentlyInPlay.index(where: ({($0?.cardID == currentCardsSelected[0].cardID)}))!
let indexOfSecondCard = cardsCurrentlyInPlay.index(where: ({($0?.cardID == currentCardsSelected[1].cardID)}))!
let indexOfThirdCard = cardsCurrentlyInPlay.index(where: ({($0?.cardID == currentCardsSelected[2].cardID)}))!
if deck.isEmpty && selectedCardsMakeASet() {
/* Remove the old cards */
cardsCurrentlyInPlay.remove(at: indexOfFirstCard)
cardsCurrentlyInPlay.remove(at: indexOfSecondCard)
cardsCurrentlyInPlay.remove(at: indexOfThirdCard) // where code is blowing up
currentCardsSelected.removeAll()
/* Return indicies of cards to clear from the UI */
return .deckIsEmpty(indexOfFirstCard, indexOfSecondCard, indexOfThirdCard)
}
The index you’re getting is correct when your get it, but it becomes wrong when you remove other cards. Consider:
var a = ["x", "y", "z"]
let indexOfX = a.index(of: "x")! // returns 0
let indexOfZ = a.index(of: "z")! // returns 2
a.remove(at: indexOfX) // removes "x"; now a = ["y", "z"]
a.remove(at: indexOfZ) // index 2 is now out of bounds
You could interleave the calls to index(of:) and remove(at:), but a better approach would be to remove all three cards in a single pass, something like this:
let selectedCardIDs = currentCardsSelected.map { $0.cardID }
cardsCurrentlyInPlay = cardsCurrentlyInPlay.filter { card in
!selectedCardIDs.contains(card.cardID)
}
Note that this has the added benefit of avoiding the force unwrap, a sign of sounder logic.
This is because of out of bounds.
After the first two code excuted.
cardsCurrentlyInPlay.remove(at: indexOfFirstCard) &
cardsCurrentlyInPlay.remove(at: indexOfSecondCard)
there is only one element in the cardsCurrentlyInPlay .
Then if you excute cardsCurrentlyInPlay.remove(at: indexOfThirdCard), the program will crash.

how to add object to one array from another

what i am trying to do is loop through an array of images (parentArray) to add the image to 5 different arrays according to what kind of image it is and when i add an image i want to remove that image from the parentArray. ive tried this but i get a thread error. any ideas would help. thanks in advance.
the code :
var index = parentArray.count
for i in parentArray {
if i.Type == Kind.S && i.cState == Color.blue {
parentArray.removeAtIndex(index)
childArray1.append(i)
}
Indexing starts at zero, so parentArray.count will be accessing out of bounds memory.
A second error is that once you have removed one element from parentArray (assuming you were accessing the last index), its total size is less. However, next element you try to remove is the same number, which causes another array indexing issue. Good luck.
Your error is because you are trying to remove the object from the index parentArray.count which will always be out of the bounds of the array index. You also never change the value of index. So each time your if statement is met, it will try and remove from the index parentArray.count.
var index = 0
for i in parentArray {
if i.Type == Kind.S && i.cState == Color.blue {
parentArray.removeAtIndex(index)
childArray1.append(i)
}
else {
i++
}
}

I want to add the values of 2 UILabels together to display the results in a separate UILabel

//un-wrap string in label and cast to Int
let made = ShotsMadeLabel.text?.toInt() //shots made Int
let miss = ShotsMissedLabel.text?.toInt() //shots missed Int
// check to see if both values are not equal to zero
// add values and display answer (ans)in TotshotShotsMadelabel
if (miss != 0) || (made != 0){
var ans = made! + miss!
TotalShotsMadeLabel.text = "\(ans)"
println(ans) // check results
per request provided clarity to my question.. please let me know if there is a better way to do this..
Your code looks good but it fails to cover the case where one of the labels' text is empty or not a number. In that case, made or miss can be nil and you will crash when you force-unwrap it (with the exclamation mark).
So, you'd need to add another level of safety:
if (miss != 0) || (made != 0) {
if (miss != nil) && (made != nil) {
var ans = made! + miss!
}
}
But the truth is that you should not be doing this in the first place. Do not store state in a view like a label! This whole business of extracting the text from a label and turning it into a number is just wrong. You should have model variables in your code that are actual numbers, maintaining this information. When they change, change the labels. And that way, you can just add them. MVC, model-view-controller. Do not use View as Model, which is what you are doing.

Resources