Get All Value in Array except "x" value Swift 3 - swift

I'm new in IOS programming. I have a question, how to get all value in array except x value. Let say i have array like below :
let array : [Any] = [1,2,3,4,5,6,7,8,9,0,11,22,33,44,55,66,77,200]
how to print all value except 1 and 2.
I have read this , its using filter and i try it with playground but i still not have the right value. Any answer will helpfull for me. Thanks in advance .

I don't know why you have defined the array as [Any] so I just removed that and the array is:-
let array = [1,2,3,4,5,6,7,8,9,0,11,22,33,44,55,66,77,200]
Next you can use filter as follows:-
let filtered = array.filter { (element) -> Bool in
return element != 1 && element != 2
}
You can test this out in the playground, it will print all values except 1 & 2
You can also use some syntactical sugar for filter as follows:-
array.filter({ return $0 != 1 && $0 != 2 })
And since the closure is a trailing argument, you can also separate it from the arguments as follows:-
array.filter { return $0 != 1 && $0 != 2 }
Another way to do this would be
let filterTheseOut = [1,2]
let anotherWay = array.filter { !filterTheseOut.contains($0) }
So here you can basically add all the elements to be filtered out in a separate array

You can do it like this
let array : [Int] = [1,2,3,4,5,6,7,8,9,0,11,22,33,44,55,66,77,200]
print(array.filter { $0 != 1 && $0 != 2 } )
or if you will have more than 1 or 2 values you can put them into array
let array : [Int] = [1,2,3,4,5,6,7,8,9,0,11,22,33,44,55,66,77,200]
let unwantedValues = [1,2]
print(array.filter { unwantedValues.contains($0) == false } )
Next time please paste your code, it will be easier to tell you what you're doing wrong, then giving you ready solution.

No need for filter use this:
for i in array {
if i != 1 && i != 2 {
print i
}
}
// This will print all values except 1 and 2

Related

Why is my app freezing when func is called

Whenever I call this function, my app freezes and nothing in the debug console prints. I am trying to get strings and a double from firebase and then stick them into an identifiable struct array. Any Ideas???
If you have another idea for storing that object, I would love to read it.
var count = Int()
var name = Array<String>()
var imageUrl = Array<String>()
var id = Array<String>()
var rating = Array<Double>()
var url = Array<String>()
var keys = 0
db.collection("parties").document(Utilities.code).addSnapshotListener { document, error in
//check for error
if error == nil {
//check if document exists
print("No error")
if document != nil && document!.exists {
print("Document Exists")
if let array = document!.get("yesName") as? Array<String> {
count = array.count
name = array
print("yesName = \(array)")
keys += 1
}
if let array = document!.get("yesImg") as? Array<String> {
imageUrl = array
print("yesImg = \(array)")
keys += 1
}
if let array = document!.get("yesId") as? Array<String> {
id = array
print("yesId = \(array)")
keys += 1
}
if let array = document!.get("yesRating") as? Array<Double> {
rating = array
print("yesRating = \(array)")
keys += 1
}
if let array = document!.get("yesUrl") as? Array<String> {
url = array
print("yesUrl = \(array)")
keys += 1
}
}
}else {
print("error = \(error!)")
}
}
while keys < 6 {
if name.count > 0 && imageUrl.count > 0 && id.count > 0 && rating.count > 0 && url.count > 0 {
for _ in 0...count {
yes.list.append(RestaurantListViewModel(name: name.first!, imageUrl: URL(string: imageUrl.first!)!, id: id.first!, rating: rating.first!, url: url.first!))
print("combined = \(yes.list.append(RestaurantListViewModel(name: name.first!, imageUrl: URL(string: imageUrl.first!)!, id: id.first!, rating: rating.first!, url: url.first!)))")
name.removeFirst()
imageUrl.removeFirst()
id.removeFirst()
rating.removeFirst()
url.removeFirst()
}
keys = 6
}
}
The snapshot listener will execute asynchronously that means in some time after the current method is finished. So the code after it is called is executed only once and just after listener creation : there is nothing yet in the arrays and keys == 0. May be this code should be inside the listener call after document is read and array updated.
Have you tried to debug while keys < 6 { circle?
Next line condition
if name.count > 0 && imageUrl.count > 0 && id.count > 0 && rating.count > 0 && url.count > 0
can easily equals to false and you get infinity circle running.
Also I see few logic issues in your code: in the first part of code you set up required fields (keys equals in a range from 0 to 6). But in the second part inside circle while keys < 6 you require all 6 fields and want to exit only after all values will have count > 0. You need to get value.count only when it needed.

Swift : affect struct by reference or "alias" to a variable

I have to update a struct, but this struct needs a long expression to be found from my viewController :
let theMessage:Message? = self.messageSections.first(where: { $0.date == DateDMY(fromNSDate:msg.date) })?
.msgs.first(where: { $0 == msg })
I want to mutate one property of this struct, but not a copy of it, I want to update it "where it is", that is in messageSections[].msgs[]
The problem here is that if I try this code after the one above :
theMessage.status = .NOT_SENT
Only the local copy will be updated, and not the real one in messageSections[].msgs[]. So when I reload my collectionView, nothing changes.
I could do
self.messageSections.first(where: { $0.date == DateDMY(fromNSDate:msg.date) })?
.msgs.first(where: { $0 == msg }).status = .NOT_SENT
But if I have to manipulate this property several times in my function, I dont want to re-write the whole expression each time. So what I'm looking for is something like in C :
let theMessage:Message?* = &self.messageSections.first(where: { $0.date == DateDMY(fromNSDate:msg.date) })?
.msgs.first(where: { $0 == msg })
if(theMessage != NULL)
theMessage->status = .NOT_SENT
I saw in other questions that I could use & before argument and inout before parameter name, but its only for functions calling. I'm looking for a way to create an alias for a big expression when affecting a variable, just to avoid re-writting it each time.
You can use firstIndex to get the index of the element in the array, then access the element directly using the retrieved index.
if let messageSectionIndex = self.messageSections.first(where: { $0.date == DateDMY(fromNSDate:msg.date) }), let messageIndex = self.messageSections[messageSectionIndex].msgs.firstIndex(where: { $0 == msg }) {
self.messageSections[messageSectionIndex].msgs[messageIndex].status = .NOT_SENT
}

Sorting arrays based on number of matches

I am trying to find the number of array item matches between multiple test arrays and one control array. After finding the number of matches, I want to append the test arrays to another array, sorted by number of matches between the control array and test array. For example, a test array with 3 matches would be at index 0, 2 matches at index 1, and so on.
let controlArray = ["milk", "honey"]
let test1 = ["honey", "water"]
let test2 = ["milk", "honey", "eggs"]
var sortedArrayBasedOnMatches = [[String]]()
/*I want to append test1 and test2 to sortedArrayBasedOnMatches based on how many items
test1 and test2 have in common with controlArray*/
/*in my example above, I would want sortedArrayBasedOnMatches to equal
[test2, test1] since test 2 has two matches and test 1 only has one*/
This can be done in a very functional and Swiftish way by writing a pipeline to process the input arrays:
let sortedArrayBasedOnMatches = [test1, test2] // initial unsorted array
.map { arr in (arr, arr.filter { controlArray.contains($0) }.count) } // making pairs of (array, numberOfMatches)
.sorted { $0.1 > $1.1 } // sorting by the number of matches
.map { $0.0 } // getting rid of the match count, if not needed
Update As #Carpsen90 pointed out, Switf 5 comes with support for count(where:) which reduces the amount of code needed in the first map() call. A solution that makes use of this could be written along the lines of
// Swift 5 already has this, let's add it for current versions too
#if !swift(>=5)
extension Sequence {
// taken from the SE proposal
// https://github.com/apple/swift-evolution/blob/master/proposals/0220-count-where.md#detailed-design
func count(where predicate: (Element) throws -> Bool) rethrows -> Int {
var count = 0
for element in self {
if try predicate(element) {
count += 1
}
}
return count
}
}
#endif
let sortedArrayBasedOnMatches = [test1, test2] // initial unsorted array
.map { (arr: $0, matchCount: $0.count(where: controlArray.contains)) } // making pairs of (array, numberOfMatches)
.sorted { $0.matchCount > $1.matchCount } // sorting by the number of matches
.map { $0.arr } // getting rid of the match count, if not needed
Another change in style from the original solution is to use labels for the tuple components, this makes the code a little bit clearer, but also a little bit more verbose.
One option is to convert each array to a Set and find the count of elements in the intersection with controlArray.
let controlArray = ["milk", "honey"]
let test1 = ["honey", "water"]
let test2 = ["milk", "honey", "eggs"]
var sortedArrayBasedOnMatches = [ test1, test2 ].sorted { (arr1, arr2) -> Bool in
return Set(arr1).intersection(controlArray).count > Set(arr2).intersection(controlArray).count
}
print(sortedArrayBasedOnMatches)
This will cover the case where elements are not unique in your control array(such as milk, milk, honey...) and with any number of test arrays.
func sortedArrayBasedOnMatches(testArrays:[[String]], control: [String]) -> [[String]]{
var final = [[String]].init()
var controlDict:[String: Int] = [:]
var orderDict:[Int: [[String]]] = [:] // the value is a array of arrays because there could be arrays with the same amount of matches.
for el in control{
if controlDict[el] == nil{
controlDict[el] = 1
}
else{
controlDict[el] = controlDict[el]! + 1
}
}
for tArr in testArrays{
var totalMatches = 0
var tDict = controlDict
for el in tArr{
if tDict[el] != nil && tDict[el] != 0 {
totalMatches += 1
tDict[el] = tDict[el]! - 1
}
}
if orderDict[totalMatches] == nil{
orderDict[totalMatches] = [[String]].init()
}
orderDict[totalMatches]?.append(tArr)
}
for key in Array(orderDict.keys).sorted(by: >) {
for arr in orderDict[key]! {
final.append(arr)
}
}
return final
}

Swift: How to use more than one 'where' on conditional binding?

I did some google searched and the examples use " , " to use more than one where statement but it doesn't work for me. I have tried && as well.
if let movesDict = pokemonInfoDict["moves"] as? [Dictionary<String,AnyObject>] where movesDict.count > 0, movesDict["learn_type"] == "level up"{
}
if let movesDict = pokemonInfoDict["moves"] as? [Dictionary<String,AnyObject>] where movesDict.count > 0 && movesDict["learn_type"] == "level up"{
}
Any help would be greatly appreciated thanks.
You want && - you must have some other problem with your code, as this works:
let foo: Int? = 10
if let bar = foo where bar > 8 && bar % 2 == 0 {
print("It works")
}
You tried this:
if let movesDict = pokemonInfoDict["moves"] as? [Dictionary<String,AnyObject>]
where movesDict.count > 0
&& movesDict["learn_type"] == "level up"
{
// ...
}
The problem is that movesDict is a array of dictionaries, and you tried to use the string "learn_type" as the subscript of that array when you said movesDict["learn_type"], but an array subscript must be an Int.

Unwrapping optional inside of closure using reduce

I have a quick question that is confusing me a little bit. I made a simple average function that takes an array of optional Ints. I check to make sure the array does not contain a nil value but when I use reduce I have to force unwrap one of the two elements in the closure. Why is it that I only force unwrap the second one (in my case $1!)
func average2(array: [Int?]) -> Double? {
let N = Double(array.count)
guard N > 0 && !array.contains({$0 == nil}) else {
return nil
}
let sum = Double(array.reduce(0) {$0+$1!})
let average = sum / N
return average
}
I know it is simple but I would like to understand it properly.
The first parameter of reduce is the sum, which is 0 in the beginning. The second one is the current element of your array which is an optional Int and therefore has to be unwrapped.
Your invocation of reduce does this:
var sum = 0 // Your starting value (an Int)
for elem in array {
sum = sum + elem! // This is the $0 + $1!
}
EDIT: I couldn't get a more functional approach than this to work:
func average(array: [Int?]) -> Double? {
guard !array.isEmpty else { return nil }
let nonNilArray = array.flatMap{ $0 }
guard nonNilArray.count == array.count else { return nil }
return Double(nonNilArray.reduce(0, combine: +)) / Double(nonNilArray.count)
}
You can also discard the second guard if you want something like average([1, 2, nil]) to return 1.5 instead of nil