Swift Remove a given value from an array - iphone

I have a simple array with
var specs : [String] = [Button1,Button2,Button3,Button4]
How can I find a certain value (type Button3) in my erray and therefore cancel?

You can use the find() global function to retrieve the index:
var specs : [String] = ["Button1","Button2","Button3","Button4"]
let index = find(specs, "Button3")
and then, once verified that the element exists (find returns an optional), remove it:
if let index = index {
specs.removeAtIndex(index)
}

Related

Error while inserting data in a Set Swift 4

I am trying to insert multiple values in a Set. So, I did this
var skuSet: Set = Set<String>()
{
(response, error) in
if (error != nil)
{
print("Error \(error.debugDescription)")
}
else
{
if let result = response.arrayObject as? Array<Dictionary<String, Any>>
{
self.coinsArr = result
let multiple = result.compactMap{ $0["sku"] as? String }
self.skuSet.insert(multiple)
}
}
But, the insert line throws the error
Cannot convert value of type '[String]' to expected argument type 'String'.
Any help?
insert is for a single item. Use formUnion to insert multiple items from a Sequence into a Set
self.skuSet.formUnion(multiple)
And if you want to replace the contents of the set with the multiple array simply write
self.skuSet = Set(multiple)
The documentation for compactMap(_:) says:
compactMap(_:) returns an array containing the non-nil results of
calling the given transformation with each element of this sequence.
However, the documentation for set insert(_:) also says:
insert(_:) inserts the given element in the set if it is not already
present.
You assign an array of strings to multiple, and expect to insert this array using insert(_:) but it's not possible.
Add the below function to Set extension in order to insert multiple elements:
func insert(_ elements: [Set.Element]) {
elements.forEach { (element) in
self.insert(element)
}
}
Alternatively, use formUnion(_:):
self.skuSet.formUnion(multiple)
...or use its immutable version, union(_:):
var skuSetUnionMultiple = self.skuSet.union(multiple)

How do I update Swift Dictionary values of mixed types, in particular Arrays

I have a dictionary of mixed types (string, NSImage, and an Array). When appending to the array, I get the error "Value of type 'Any??' has no member 'append'". I don't see how to cast "file_list" value as an Array so I can append values to it.
var dataDict: [String:Any?] = [
"data_id" : someString,
"thumbnail" : nil,
"file_list" : [],
]
// do stuff... find files... whirrr wizzzz
dataDict["thumbnail"] = NSImage(byReferencingFile: someFile)
dataDict["file_list"].append( someFile ) <- ERROR: Value of type 'Any??' has no member 'append'
You can't. You need to first get your key value, cast from Any to [String], append the new value and then assign the modified array value to your key:
if var array = dataDict["file_list"] as? [String] {
array.append(someFile)
dataDict["file_list"] = array
}
or
if let array = dataDict["file_list"] as? [String] {
dataDict["file_list"] = array + [someFile]
}
Another option is to create a custom struct as suggested in comments by OOPer

Swift dictionary, a key with multiple values

I would like to know how I can make a key of a dictionary have multiple values according to the data that comes to it.
Attached basic example:
var temp = [String: String] ()
temp ["dinningRoom"] = "Table"
temp ["dinningRoom"] = "Chair"
In this case, I always return "Chair", the last one I add, and I need to return all the items that I am adding on the same key.
In this case, the "dinningRoom" key should have two items that are "Table" and "Chair".
You can use Swift Tuples for such scenarios.
//Define you tuple with some name and attribute type
typealias MutipleValue = (firstObject: String, secondObject: String)
var dictionary = [String: MutipleValue]()
dictionary["diningRoom"] = MutipleValue(firstObject: "Chair", secondObject: "Table")
var value = dictionary["diningRoom"]
value?.firstObject
You can declare a dictionary whose value is an array and this can contain the data you want, for example:
var temp = [String: [String]]()
temp["dinningRoom"] = ["Table", "Chair", "Bottle"]
If you want to add a new element you can do it this way:
if temp["dinningRoom"] != nil {
temp["dinningRoom"]!.append("Flower")
} else {
temp["dinningRoom"] = ["Flower"]
}
Now temp["dinningRoom"] contains ["Table", "Chair", "Bottle", "Flower"]
Use Dictionary like this:
var temp = [String: Any]()
temp["dinningRoom"] = ["Table", "Chair"]
If you want to fetch all the elements from dinningRoom. You can use this:
let dinningRoomArray = temp["dinningRoom"] as? [String]
for room in dinningRoomArray{
print(room)
}
It is not compiled code but I mean to say that we can use Any as value instead of String or array of String. When you cast it from Any to [String]
using as? the app can handle the nil value.

Swift rating system loop and assign

Trying to build a rating system in Swift and looking for a cleaner way to loop through each of the values.
private func calculateRating(user: String) throws -> String {
let query = try Rating.makeQuery().filter("user", user).all()
var fiveStars = [Int]()
var fourStars = [Int]()
var threeStars = [Int]()
var twoStars = [Int]()
var onestar = [Int]()
if query.count > 1 {
for rating in query {
// Check each value and assign it to its associated value
// insert large if/else condition here :)
}
// Perform calculation and return value below
return ""
} else {
// Only one rating has been set
return query[0].value
}
}
Currently I'm looping through each of the values and assigning the rating to it's associated array fiveStars fourStars etc. I will then calculate the rating by the standard multiplication method. Is there a cleaner way to loop through the ratings and assign it to the relevant fiveStars array etc without creating a long if/else conditional?
Thanks
Edit: Sample output would be a single rounded up value out of 5 i.e. "4" out of five based on 1000's of multiple ratings.
let twoStars: [Int] = query.filter {$0.val == 2} .map {$0.val}
And so on.

How to sort an array in Swift

I want the Swift version of this code:
NSArray *sortedNames = [names sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
var names = [ "Alpha", "alpha", "bravo"]
var sortedNames = names.sorted { $0.localizedCaseInsensitiveCompare($1) == NSComparisonResult.OrderedAscending }
Update: Providing explanation as per recommendation of a fellow SO user.
Unlike ObjC, in Swift you have sorted() (and sort()) method that takes a closure that you supply that returns a Boolean value to indicate whether one element should be before (true) or after (false) another element. The $0 and $1 are the elements to compare. I used the localizedCaseInsensitiveCompare to get the result you are looking for. Now, localizedCaseInsensitiveCompare returns the type of ordering, so I needed to modify it to return the appropriate bool value.
Update for Swift 2:
sorted and sort were replaced by sort and sortInPlace
Sorting an Array in Swift
Define a initial names array:
var names = [ "gamma", "Alpha", "alpha", "bravo"]
Method 1:
var sortedNames = sorted(names, {$0 < $1})
// sortedNames becomes "[Alpha, alpha, bravo, gamma]"
This can be further simplified to:
var sortedNames = sorted(names, <)
// ["Alpha", "alpha", "bravo", "gamma"]
var reverseSorted = sorted(names, >)
// ["gamma", "bravo", "alpha", "Alpha"]
Method 2:
names.sort(){$0 < $1}
// names become sorted as this --> "[Alpha, alpha, bravo, gamma]"
If your array does not contain Custom Objects (just a string or number type):
var sortedNames = sorted(names, <)
Otherwise if you create a Custom Data Object Class containing custom properties inside:
customDataObjectArray.sort({ $0.customProperty < $1.customProperty })
Most efficient way of sorting in SWIFT
The use of Operator Overloading is the most efficient way to sort Strings in Swift language.
// OPERATOR OVERLOADING
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
var sortedNames = sorted(names, <)
var reverseOrder = sorted(names, >)
In above code > and < operators are overloaded in Swift to sort Strings.
I have test the code in Playground and conclude that when we use operator overloading it is best for sorting Strings.
Copy below to Playground.
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
var reversed = sorted (names,
// This is a closure
{ (s1 : String, s2 : String) -> Bool in
return s1 > s2
}
)
println(reversed)
var reverseOrder = sorted(names, {s1, s2 in s1 > s2})
var reverseOrder2 = sorted(names, { $0 > $1} )
// OPERATOR OVERLOADING
var reverseOrder3 = sorted(names, >)
The conclusion from Playground:
From above image you can see that all other ways needs to enumerate loops for sorting 5 strings. Where as when we use Operator overloading it does not required to enumerate loop to sort strings.
Referenced from Swift documentation
If you want to sort your array in ascending order then use below syntax:
var arrayName = sorted(arrayName, <)
as the sorted() is the predefined function in swift and < is used to indicate that the array should be sorted in ascending order. If you want to sort the array in descending order then simply replace < with > as I have shown below:
var arrayName = sorted(arrayName, >)
You can usually use the built-in
func sort<T : Comparable>(inout array: [T])
but if you want to use localizedCaseInsensitiveCompare:, your code can be translated directly using NSArray.
Any method that can be used with Objective-C sortedArrayUsingSelector: can be used with Swift sort (or sorted) provided the type of thing in the array is known. So, in your code:
var arr : [String] = // ...
// it is an array of String, so we can use localizedCaseInsensitiveCompare:
sort(&arr) {return $0.localizedCaseInsensitiveCompare($1) == .OrderedAscending}
Similarly:
var events : [EKEvent] = // ...
sort(&events) {return $0.compareStartDateWithEvent($1) == .OrderedAscending}
In Swift-
let students: Set = ["Kofi", "Abena", "Peter", "Kweku", "Akosua"]
let sortedStudents = students.sorted()
print(sortedStudents)
// Prints "["Abena", "Akosua", "Kofi", "Kweku", "Peter"]"
To sort the elements of your sequence in descending order, pass the greater-than operator (>) to the sorted(isOrderedBefore:) method.
let descendingStudents = students.sorted(isOrderedBefore: >)
print(descendingStudents)
// Prints "["Peter", "Kweku", "Kofi", "Akosua", "Abena"]"