Using NSMutableArray sortUsingFunction in Swift? - swift

This link tells you what your sorting function has to look like, but I just can't make a Swift function look like that.
Here's my call:
packetsArray.sortUsingFunction(comparePacketDates, context: nil)
Here's my function, and I've tried a zillion other variations of it:
static func comparePacketDates(packet1 : AnyObject, packet2: AnyObject, context: UnsafeMutablePointer<Void>) -> Int {
And I've tried using a c function instead, this and a few other variations:
NSInteger comparePacketDates(id packet1, id packet2, void* dummy);
It's always "cannot invoke with argument list ..." saying the function isn't what's expected as the first argument.
Does anyone have example code of a Swift function that would be accepted as the first argument of the Swift sortUsingFunction? Or even a c function that would be accepted as the first argument of the Swift SortUsingFunction?

Use sortUsingComparator. It's simpler than sortUsingFunction. Here's the syntax:
a.sortUsingComparator {
let packet1 = $0 as! Packet
let packet2 = $1 as! Packet
if packet1.timestamp < packet2.timestamp {
return .OrderedAscending
}
if packet1.timestamp == packet2.timestamp {
return .OrderedSame
}
return .OrderedDescending
}

Here is an example for your reference that I wrote:
var ma = NSMutableArray()
ma.addObject("Hi")
ma.addObject("Anil")
func comp(first: AnyObject, second:AnyObject, context: UnsafeMutablePointer<Void>) -> Int {
let f:String = first as! String
let s:String = second as! String
if f > s {
return 1
}
else if ( f == s ) {
return 0
}
return -1
}
ma.sortUsingFunction(comp, context:UnsafeMutablePointer<Void>(bitPattern: 0))
HTH, as a reference to you. Note: I am in Xcode 7.1 Swift 2.1.

Related

Is there a way to retrieve directly the value returned from a closure in Swift, with type the return type of the closure and not: () -> Type

This is a question that aims merely at elegance, but is there a way to make something to the following code work in Swift? I know the code does not work, what I want is that the result of the code within the closure is stored in a constant. And the underlying theoretical issue is whether or not it is possible to retrieve the returned value from the closure with type Int and not with type () -> Int.
Thanks a lot for any help or comment!
let tableWithBooleans: [Bool] = Array(repeating: false, count: 10)
tableWithBooleans[0] = true
tableWithBooleans[5] = true
let numberOfTrue: Int = {
var result: Int = 0
for i in 0...9 {
if tableWithBooleans[i] {
result += 1
}
}
return result
}
// I want the code to compile and numberOfTrue to be a constant equal to 2
Use a high-order function instead
let numberOfTrue = tableWithBooleans.reduce(0) { $1 ? $0 + 1 : $0 }
Now if you still want to use your closure code then you should add a () after the closing } since you are calling the code inside {} as a function
let numberOfTrue: Int = {
var result: Int = 0
for i in 0...9 {
if tableWithBooleans[i] {
result += 1
}
}
return result
}()

How to check if a string contains multiple characters in Swift 5

I have a failure initializer that takes a string, if this string contains incorrect characters (T, A, C, G) I want to return nil:
I tried something like this, unsuccessful:
init?(strand: String) {
let success = strand.contains(where: { !"TACG".contains($0) })
if !success {
return nil
}
self.strand = strand
}
I somehow got confused by the two contains calls, so I am not sure if my check is correct.
Any help is appreciated.
In this case I'd prefer the API rangeOfCharacter(from which checks the string against a character set
init?(strand: String) {
guard strand.rangeOfCharacter(from: CharacterSet(charactersIn: "TACG")) == nil else { return nil }
self.strand = strand
}
If you don't want to import Foundation you can also use Collection method allSatisfy
func allSatisfy(_ predicate: (Character) throws -> Bool) rethrows -> Bool
And make sure your string contains all characters
let allSatisfy = "CGAT".allSatisfy("TACG".contains)
print(allSatisfy) // true
Just move the ! placement, check out the code below .
init?(strand: String) {
let success = !strand.contains(where: { "TACG".contains($0) })
if !success {
return nil
}
self.strand = strand
}

How do you write a generic function to do conditional downcasting in Swift?

My goal is to write something that can convert something like [AnyObject] to Result<[SomeObject], NSError> to easily do safe and chainable casting while working with a mixed Swift/Obj-C codebase. The conditional downcast operator as? seems to support that just fine, but I can't get a generic function working that utilizes that behavior. I've simplified the problem I'm encountering below:
class A { }
let obj = A()
let array: [AnyObject] = [obj]
func cast<T, U>(x: T, type: U.Type) -> U? {
if let x = x as? U {
return x
} else {
return nil
}
}
// This works
if let array = array as? [A] {
println(array)
}
// This works
println(cast(obj, A.self))
// This doesn't
println(cast(array, [A].self))
Note: This works in Swift 2.0, I don't know about 1.2, try it out
If you want to do something like this you'd have to overload your cast method with one for SequenceTypes:
func cast<T : SequenceType, U : SequenceType>(x: T, type: U.Type) -> [U.Generator.Element]? {
let y = x.map{ $0 as? U.Generator.Element }
if y.contains({ $0 == nil }) {
return nil
} else {
return y.flatMap{ $0 } // Swift 1.2 : y.map{ $0! }
}
}
EDIT: Changed according to your edit
Generally, Swift doesn't support GenericType<A> as? GenericType<B> cast, even if B is a subtype of A. Array<A> as? Array<B> is just a exception for our convenience.
There is a undocumented internal builtin function:
func _arrayConditionalDownCastElements<SourceElement, TargetElement>(a: Array<SourceElement>) -> [TargetElement]?
With my assumption, Swift implicitly calls this function when we do someArray as? [B]. But, with a generics type, just like your case, the Swift compiler cannot bind that to _arrayConditionalDownCastElements because it's unpredictable in compile time.
Anyway, you can call it manually, and implement cast as overloaded function:
func cast<T,U>(x:T, _: U.Type) -> U? {
return x as? U
}
func cast<T,U>(x:[T], _: [U].Type) -> [U]? {
return _arrayConditionalCast(x)
}
Similarly, there is _dictionaryDownCastConditional for Dictionary and _setDownCastConditional for Set:
func _dictionaryDownCastConditional<BaseKey, BaseValue, DerivedKey, DerivedValue>(source: Dictionary<BaseKey, BaseValue>) -> Dictionary<DerivedKey, DerivedValue>?
func _setDownCastConditional<BaseValue, DerivedValue>(source: Set<BaseValue>) -> Set<DerivedValue>?
Using this:
func cast<TKey,TValue, UKey, UValue>(x:[TKey: TValue], _: [UKey:UValue].Type) -> [UKey: UValue]? {
return _dictionaryDownCastConditional(x)
}
func cast<T, U>(x: Set<T>, _: Set<U>.Type) -> Set<U>? {
return _setDownCastConditional(x)
}
Again, they are undocumented. use them at your own risk :)

Recursion over a Swift Sliceable

I feel that I must be missing something obvious. Decomposing a list into the head and tail and then recursing over the tail is a standard functional programming technique, yet I'm struggling to do this for Sliceable types in Swift.
I have a recursive function that follows this pattern:
func recurseArray(arr: [Int]) -> [Int] {
guard let first = arr.first else {
return []
}
let rest = recurseArray(Array(dropFirst(arr)))
let next = rest.first ?? 0
return [first + next] + rest
}
Obviously the real code does a lot more than add each number to the next.
Note the call to Array(dropFirst(seq)). Converting to an Array is required since dropFirst actually returns an ArraySlice, and an ArraySlice isn't a Sliceable, so I can't pass it to my function.
I'm not sure what sort of optimization the compiler is capable of here, but it seems to me that creating a new array from a SubSlice unnecessarily won't be optimal. Is there a solution to this?
Furthermore, what I'd really like to do is create a version of this function that can take any Sliceable type:
func recurseSeq<T: Sliceable where T.Generator.Element == Int>(list: T) -> [Int] {
guard let first = list.first else {
return []
}
let rest = recurseSeq(dropFirst(list)) // <- Error - cannot invoke with argument type T.SubSlice
let next = rest.first ?? 0
return [first + next] + rest
}
This time I don't have a solution to the fact that I have a SubSlice. How can I achieve my goal?
It turns out that there is a generic solution. You need to add these generic requirements:
<
S : Sliceable where S.SubSlice : Sliceable,
S.SubSlice.Generator.Element == S.Generator.Element,
S.SubSlice.SubSlice == S.SubSlice
>
For the question posted, this gives:
func recurseSeq<
S : Sliceable where S.SubSlice : Sliceable,
S.SubSlice.Generator.Element == Int,
S.SubSlice.SubSlice == S.SubSlice,
S.Generator.Element == Int
>(list: S) -> [Int] {
guard let first = list.first else {
return []
}
let rest = recurseSeq(dropFirst(list))
let next = rest.first ?? 0
return [first + next] + rest
}
Here's a useful generic reduce on any sliceable:
extension Sliceable where
SubSlice : Sliceable,
SubSlice.Generator.Element == Generator.Element,
SubSlice.SubSlice == SubSlice {
func recReduce(combine: (Generator.Element, Generator.Element) -> Generator.Element) -> Generator.Element? {
return self.first.map {
head in
dropFirst(self)
.recReduce(combine)
.map {combine(head, $0)}
?? head
}
}
}
[1, 2, 3].recReduce(+) // 6
I can't take credit for this, the solution was posted on the Apple Development Forums.
It's a shame that the generic requirements are so involved for such a a basic operation - it's hardly intuitive! But I'm glad to have a solution...
Actually ArraySlice is Sliceable, so you can recurse on
ArraySlice<Int>:
func recurseArray(arr: ArraySlice<Int>) -> [Int] {
guard let first = arr.first else {
return []
}
let rest = recurseArray(dropFirst(arr))
let next = rest.first ?? 0
return [first + next] + rest
}
with a wrapper function which is called only once at the top level:
func recurseArray(arr: [Int]) -> [Int] {
return recurseArray(arr[arr.startIndex ..< arr.endIndex])
}
I don't have a solution for your second more general problem.
The API docs for Sliceable state that SubSlice should be
Sliceable itself (which is the case for all known Sliceable
types).
I have therefore the feeling that it should be possible by requesting
that T.SubSlice is itself sliceable with the identical SubSlice
type, however this does not compile:
func recurseSeq<T: Sliceable where T.Generator.Element == Int,
T.SubSlice : Sliceable,
T.SubSlice.SubSlice == T.SubSlice>(list: T.SubSlice) -> [Int] {
guard let first = list.first else {
return []
}
let rest = recurseSeq(dropFirst(list) as T.SubSlice)
// error: cannot invoke 'recurseSeq' with an argument list of type '(T.SubSlice)'
let next = rest.first ?? 0
return [first + next] + rest
}
The compiler accepts that dropFirst(list) can be cast to T.SubSlice,
but refuses to call recurseSeq() on that value, which I do not
understand.
Alternatively, you can recurse on a GeneratorType:
func recurseGen<G: GeneratorType where G.Element == Int>(inout gen: G) -> [Int] {
guard let first = gen.next() else {
return []
}
let rest = recurseGen(&gen)
let next = rest.first ?? 0
return [first + next] + rest
}
with a wrapper that takes a SequenceType:
func recurseSeq<T: SequenceType where T.Generator.Element == Int>(list: T) -> [Int] {
var gen = list.generate()
return recurseGen(&gen)
}
Arrays and array slices all conform to SequenceType, so that should
work in all your cases.
Creating an array in every iteration doesn't seem like a good idea. I don't know if the compiler optimizes it somehow, but you could probably find a different solution.
For example, in this case, you could drop de recursion and use a for loop instead that modifies the array in place.
func recurseArray2(var a: [Int]) -> [Int] {
for var i = a.count-1; i > 0; i-- {
a[i-1] += a[i]
}
return a
}

How can I find the index of an item in Swift? [duplicate]

This question already has answers here:
How to find index of list item in Swift?
(23 answers)
Closed 7 years ago.
Is there a method called indexof or something similar?
var array = ["Jason", "Charles", "David"]
indexOf(array, "Jason") // Should return 0
EDIT: As of Swift 3.0, you should use the .index(where:) method instead and follow the change in the Swift 2.0 edit below.
EDIT: As of Swift 2.0, you should use the indexOf method instead. It too returns nil or the first index of its argument.
if let i = array.indexOf("Jason") {
print("Jason is at index \(i)")
} else {
print("Jason isn't in the array")
}
Use the find function. It returns either nil (if the value isn't found) or the first index of the value in the array.
if let i = find(array, "Jason") {
println("Jason is at index \(i)")
} else {
println("Jason isn't in the array")
}
In Swift 2.0 (Xcode 7.1b), you can use
if let result = array.indexOf("Jason")
while find(array, "Jason") is deprecated.
I made this function like above, but it return array of indexes
extension Array {
func indexesOf<T : Equatable>(object:T) -> [Int] {
var result: [Int] = []
for (index,obj) in enumerate(self) {
if obj as T == object {
result.append(index)
}
}
return result
}
}
Maybe it will be useful for you
Array can be bridged to an NSArray, so you can use:
array.bridgeToObjectiveC().indexOfObject("Jason")
An extension of Array can work wonders here. Here's an implementation shared in this StackOverflow answer:
extension Array {
func find (includedElement: T -> Bool) -> Int? {
for (idx, element) in enumerate(self) {
if includedElement(element) {
return idx
}
}
return nil
}
}
You can add an Array Extension that does exactly what you want, i.e:
extension Array {
func indexOf<T : Equatable>(x:T) -> Int? {
for i in 0..self.count {
if self[i] as T == x {
return i
}
}
return nil
}
}
Which now lets you use .indexOf() on all Swift arrays, e.g:
["Jason", "Charles", "David"].indexOf("Jason") //0
While the response from Max is great, it does not let you find multiple indexes of multiple objects, ie. indexes of the subset of the array. If you need that functionality, extensions are, as always, your best friend
func indexesOfSubset<T : Equatable>(objects : [T]) -> [Int] {
// Create storage for filtered objectsand results
var unusedObjects = objects
var result : [Int] = []
// Enumerate through all objects in array
for (index, obj) in enumerate(self) {
// Enumerate again through all objects that has not been found
for x in unusedObjects {
// If we hit match, append result, remove it from usused objects
if obj as! T == x {
result.append(index)
unusedObjects = unusedObjects.filter( { $0 != x } )
break
}
}
}
// Get results
return result
}
Note* : Works on Swift 1.2, if you want compatibility with 1.1, replace as! -> as