I'm trying to implement Quick Sort in Swift and having issues recursively parsing the array into the quick_sort function. I'm receiving the error:
error: ambiguous subscript with base type '[String]' and index type 'CountableRange<Int>'
The function is:
func quick_sort(_ array: inout [String]) {
if array.count > 0 {
let pivot = array[0]
var (left, right) = partition(&array, pivot)
quick_sort(&array[0..<left])
}
}
The error is occurring on the line quick_sort(&array[0..<left]).
It may have to do with it potentially being an ArraySlice?
When you slice an Array, you get an ArraySlice. When you slice an ArraySlice, you get another ArraySlice. This property, that T.SubSequence == T, is vital to making a recursive algorithm like this, so that you only have to work with a single type.
You need your recursive function work with ArraySlice, but you can make a wrapper function that takes an Array and does the necessary conversion.
func quickSort(_ array: inout [String]) {
func quickSort(_ slice: inout ArraySlice<String>) {
if let first = slice.first {
var (left, right) = partition(&slice, pivot)
quickSort(&slice[0..<left]) // This part of the algorithm will break...
}
}
quickSort(ArraySlice(array))
}
Related
What does Element mean when writing an extension on Array?
like in this example:
extension Array {
func reduce<T>(_ initial: T, combine: (T, Element) -> T) -> T {
var result = initial
for x in self {
result = combine(result, x)
}
return result
}
}
The combine parameter is a function which takes a parameter of type T and Element. The Element is the actual Element of/in the array.
For example, this is an array of Int elements:
let arr = [1,2,5,77]
In reduce, initial is of type T. This is the staring value for the mapping you are about to perform.
In combine, T is like your starting value for each subsequent step of combing the next Element to produce another value of type T which will be used as the next T in combine, and so and so forth until the entire array has been processed.
If you were using a default use of reduce such as:
arr.reduce(0, +)
You can see that in this case, T and Element would both be of the same type, Int.
However, I could have a custom object that the array is of, and my combine is defining how to get the running total. If you had something like this:
struct Thing {
var val1: String
var val2: Int
}
let thingArray = //...define some Things in an array
You could use reduce and define your own combine function to return the sum of all the val2 values. In this case, T would be an Int, and Element would be Thing.
It is legal to say this (arr is an Array):
let arrenum = Array(arr.enumerated())
So why isn't it legal to say this?
extension Array {
func f() {
let arrenum = Array(self.enumerated())
// error: type of expression is ambiguous without more context
}
}
EDIT It seems this is a workaround:
extension Array {
func f() {
typealias Tup = (offset:Index, element:Element)
let arrenum = Array<Tup>(self.enumerated())
}
}
But why is that needed? (And is it right?)
This is a known bug (SR-1789). Swift currently has a feature where you can refer to a generic type within its own body without having to repeat its placeholder type(s) – the compiler will infer them for you to be the same as the type of self.
For example:
struct S<T> {
func foo(_ other: S) { // parameter inferred to be `S<T>`.
let x = S() // `x` inferred to be `S<T>`.
}
}
extension S {
func bar(_ other: S) {} // same in extensions too.
}
This is pretty convenient, but the bug you're running into is the fact that Swift will always make this inference, even if it's incorrect.
So, in your example:
extension Array {
func f() {
let arrenum = Array(self.enumerated())
// error: type of expression is ambiguous without more context
}
}
Swift interprets the code as let arrenum = Array<Element>(self.enumerated()), as you're in the body of Array<Element>. This is incorrect, because enumerated() yields a sequence of offset-element tuple pairs – Swift should have inferred Array to be Array<(offset: Int, element: Element)> instead.
One workaround, which you've already discovered, is to explicitly specify the placeholder type in order to prevent the compiler from making this incorrect inference.
extension Array {
func f() {
let arrenum = Array<(offset: Int, element: Element)>(self.enumerated())
}
}
Another possible workaround appears to be using the fully-qualified type, for example:
extension Array {
func f() {
let arrenum = Swift.Array(self.enumerated())
}
}
as it appears Swift doesn't do the same inference for fully-qualified types (I'm not sure if you should rely on this fact though).
Finally it's worth noting that instead of doing a call to Array's initialiser, you could use map(_:) instead to avoid the issue entirely:
extension Array {
func f() {
let arrenum = self.enumerated().map { $0 }
}
}
which, like the initialiser call, will give you back an array of offset-element pairs.
I have an extension to Dictionary that adds map, flatMap, and filter. For the most part it's functional, but I'm unhappy with how the arguments to the transform and predicate functions must be specified.
First, the extension itself:
extension Dictionary {
init<S:SequenceType where S.Generator.Element == Element>(elements: S) {
self.init()
for element in elements {
self[element.0] = element.1
}
}
func filter(#noescape predicate:(Key, Value) throws -> Bool ) rethrows -> [Key:Value] {
return [Key:Value](elements:try lazy.filter({
return try predicate($0.0, $0.1)
}))
}
}
Now then, since the predicate argument is declared as predicate:(Key, Value), I would expect the following to work:
["a":1, "b":2].filter { $0 == "a" }
however, I have to actually use:
["a":1, "b":2].filter { $0.0 == "a" }
This is kind of confusing to use since the declaration implies that there are two arguments to the predicate when it's actually being passed as a single tuple argument with 2 values instead.
Obviously, I could change the filter function declaration to take a single argument (predicate:(Element)), but I really prefer it to take two explicitly separate arguments.
Any ideas on how I can actually get the function to take two arguments?
When you are using closures without type declaration, the compiler has to infer the type. If you are using only $0 and not $1, the compiler thinks that you are declaring a closure with only one parameter.
This closure then cannot be matched to your filter function. Simple fix:
let result = ["a":1, "b":2].filter { (k, _) in k == "a" }
Now also remember that tuples can be passed to functions and automatically match the parameters:
func sum(x: Int, _ y: Int) -> Int {
return x + y
}
let params = (1, 1)
sum(params)
Then the behavior with ["a":1, "b":2].filter { $0.0 == "a" } can be explained by type inferring. There are two possibilities and the compiler just chose the wrong one because it thought you want to have a closure with one argument only - and that argument had to be a tuple.
You can add a comparison function to allow you to compare a Dictionary.Element and a Key
func ==<Key: Hashable,Value>(lhs:Dictionary<Key,Value>.Element, rhs:Key) -> Bool {
return lhs.0 == rhs
}
func mapGen<T>(transform:((T)->T),collection:Array<T>) -> Array<T> {
func cat<T>(initial:Array<T>,element:T) -> Array<T> {
var mInitial = initial;
var telement = transform(element);
mInitial.append(telement);
return mInitial;
}
var k = collection.reduce([],cat);
return k;
}
I am getting a issue trying to run this piece of code.
I new to swift can anyone help me out ?
I am trying to write a generic map out of a reduce function it does not appear to be working.
Here:
func mapGen<T>(transform:((T)->T),collection:Array<T>) -> Array<T> {
you are defining a generic type T, and in the nested function:
func cat<T>(initial:Array<T>,element:T) -> Array<T> {
you are (re)defining a new generic type with the same name, but which is actually a different type - you can even name it V or NewType, you still have the same error.
I deduct that in your case you want the nested function to use the same T type, so just do not redefine it:
func cat(initial:Array<T>,element:T) -> Array<T> {
and it should work as expected
To make the error message (which currently sounds pretty non-sensical) clearer, let's rename your type variables, so that you don't have two type variables with the same name:
func mapGen<T1>(transform:((T1)->T1),collection:Array<T1>) -> Array<T1> {
func cat<T2>(initial:Array<T2>,element:T2) -> Array<T2> {
var mInitial = initial;
var telement = transform(element);
mInitial.append(telement);
return mInitial;
}
var k = collection.reduce([],cat);
return k;
}
Now the error message becomes "T1 does not convert to T2", which makes a lot more sense. The reason that you're getting that error is the expression transform(element). element has the type T2, but transform expects an argument of type T1.
Fundamentally the problem is that you're promising that cat can work with any given type, but in reality it can only work with values of the outer T, so the solution would be to simply remove the type parameter of cat and use the outer T in the types of its arguments.
New Swift enthusiast here! I'm following Rey Wenderlich's Candy Crush tutorial and get an error when multiplying two Int values. I know Swift is strictly typed so would be the reason? Am I not allowed to do this in Swift? Note the error comments where I'm having trouble. Any help in the right direction is greatly appreciated!
class Array2D<T> {
let columns: Int
let rows: Int
let array: Array<T>
init(columns: Int, rows: Int) {
self.columns = columns
self.rows = rows
array = Array<T?>(count: rows*columns, repeatedValue: nil) // ERROR: could not find an overload for '*' that accepts the supplied arguments
}
subscript(column: Int, row: Int) -> T? {
get {
return array[row*columns + column]
}
set {
array[row*columns + column] = newValue // ERROR: could not find an overload for '*' that accepts the supplied arguments
}
}
}
Change your array to be of type T?.
In the first case, you are trying to assign array of type T? to array of type T. In the second, you are trying to assign newValue of type T? to an element of array of type T.
Changing the type of the array fixes both these things.