I like to know if I use Set instead of Array can my method of first(where:) became Complexity:O(1)?
Apple says that the first(where:) Method is O(n), is it in general so or it depends on how we use it?
for example look at these two ways of coding:
var numbers: [Int] = [Int]()
numbers = [3, 7, 4, -2, 9, -6, 10, 1]
if let searchResult = numbers.first(where: { value in value == -2 })
{
print("The number \(searchResult) Exist!")
}
else
{
print("The number does not Exist!")
}
and this:
var numbers: Set<Int> = Set<Int>()
numbers = [3, 7, 4, -2, 9, -6, 10, 1]
if let searchResult = numbers.first(where: { value in value == -2 })
{
print("The number \(searchResult) Exist!")
}
else
{
print("The number does not Exist!")
}
can we say that in second way Complexity is O(1)?
It's still O(n) even when you use a Set. .first(where:) is defined on a sequence, and it is necessary to check the items in the sequence one at a time to find the first one that makes the predicate true.
Your example is simply checking if the item exists in the Set, but since you are using .first(where:) and a predicate { value in value == -2} Swift will run that predicate for each element in the sequence in turn until it finds one that returns true. Swift doesn't know that you are really just checking to see if the item is in the set.
If you want O(1), then use .contains(-2) on the Set.
I recommend to learn more about Big-O notation. O(1) is a strict subset of O(n). Thus every function that is O(1) is also in O(n).
That said, Apple’s documentation is actually misleading as it does not take the complexity of the predicate function into account. The following is clearly O(n^2):
numbers.first(where: { value in numbers.contains(value + 42) })
Both Set and Dictionary conform to the Sequence protocol, which is the one that exposes the first(where:) function. And this function has the following requirement, taken from the documentation:
Complexity: O(n), where n is the length of the sequence.
Now, this is the upper limit of the function complexity, it might well be that some sequences optimize the search based on their data type and the storage details.
Bottom line: you need to reach the documentation for a particular type if you want to know more about the performance of some feature, however if you're only circulating some protocol references, then you should assume the "worst" - aka what's in the protocol documentation.
This is the implementation of the first(where:) function in the sequence:
/// - Complexity: O(*n*), where *n* is the length of the sequence.
#inlinable
public func first(
where predicate: (Element) throws -> Bool
) rethrows -> Element? {
for element in self {
if try predicate(element) {
return element
}
}
return nil
}
From the Swift Source Code on the Github
As you can see, It's a simple for loop and the complexity is O(n) (assuming the predicate complexity is 1 🤷🏻♂️).
The predicate executes n times. So the worst case is O(n)
The Set has not an overload for this function (since it is nonsense and there will be nothing more than the first one in a Set). If you know about the sequence and you are just looking for a value (not a predicate), just use contains or firstIndex(of:). These two have overloads with the complexity of O(1)
From the Swift Source Code on the Github
So lets say we have an array a = [20,50,100,200,500,1000]
Generally speaking we could do for number in a { print(a) } if we wanted to check the entirety of a.
How can you limit what indexes are checked? As in have a set beginning and end index (b, and e respectively), and limit the values of number that are checked to between b and e?
For an example, in a, if b is set to 1, and e is set to 4, then only a1 through a[4] are checked.
I tried doing for number in a[b...e] { print(number) }, I also saw here someone do this,
for j in 0..<n { x[i] = x[j]}, which works if we want just a ending.
This makes me think I can do something like for number in b..<=e { print(a[number]) }
Is this correct?
I'm practicing data structures in Swift and this is one of the things I've been struggling with. Would really appreciate an explanation!
Using b..<=e is not the correct syntax. You need to use Closed Range Operator ... instead, i.e.
for number in b...e {
print(a[number])
}
And since you've already tried
for number in a[b...e] {
print(number)
}
There is nothing wrong with the above syntax as well. You can use it either way.
An array has a subscript that accepts a Range: array[range] and returns a sub-array.
A range of integers can be defined as either b...e or b..<e (There are other ways as well), but not b..<=e
A range itself is a sequence (something that supports a for-in loop)
So you can either do
for index in b...e {
print(a[index])
}
or
for number in a[b...e] {
print(number)
}
In both cases, it is on you to ensure that b...e are valid indices into the array.
I'm trying to work through a problem at the moment which is currently doing the rounds on the internet. The problem is: Given an array of characters, find the first non repeating character. I had a go at it and solved it but I was curious about how other people solved it so I did some looking around and found this answer:
let characters = ["P","Q","R","S","T","P","R","A","T","B","C","P","P","P","P","P","C","P","P","J"]
var counts: [String: Int] = [:]
for character in characters {
counts[character] = (counts[character] ?? 0) + 1
}
let nonRepeatingCharacters = characters.filter({counts[$0] == 1})
let firstNonRepeatingCharacter = nonRepeatingCharacters.first!
print(firstNonRepeatingCharacter) //"Q"
Source: Finding the first non-repeating character in a String using Swift
What I don't understand about this solution, is why it always returns Q, when there are other elements "S" "A" "B" and "J" that could be put first when the filter is applied to the dictionary. My understanding of dictionaries is that they are unordered, and when you make one they change from run to run. So if I make one:
let dictionary:[String:Int] = ["P": 9, "C": 8, "E": 1]
And then print 'dictionary', the ordering will be different. Given this, can anyone explain why the solution above works and maintains the order in which the dictionary elements were added?
You are not looking correctly at the code. The filter is not applied to a dictionary. It is applied to the array (characters), which has a defined order. The dictionary is used only to store counts.
I've just stared learning swift and got stuck with functions. could someone help?
Also, I would be grateful if you could suggest me some books about Swift for beginners with simple exercises so i could practise. Thanks in advance)
There already is such a function. It's called map. It takes a closure that takes each element of the source array as input and returns a new value to use in the output array.
let ints = [1, 3, 5, 7, 9, 23, 57]
let doubled = ints.map { return $0 * 2 }
alternately, you could write your own function that takes an array of ints and returns another array of Ints:
func doubledInts(_ array: [Int]) -> [Int] {
var output = [Int]()
for value in array {
output.append(value *2)
}
return output
}
You could also get fancier, and make your function use Generics to take any scalar value (Int and it's variants like Int32, UInt32, Int8, plus Double, Float, etc) and return an array of the same type, but if you don't yet understand the basics of functions then Generics are going to be way over your head.
I learned Swift from the Apple iBook "The Swift Programming Language." I found it very informative, but your milage may vary.
First of all, this question is not about "what does $0 mean". I learnt in swift document that $0 is like index.
My question is "How numbers.sort { $0 > $1 } can be used to implement a sort function". I searched for this syntax numbers.sort { $0 > $1 } in some other websites, for example this one. It is apparently not the current version. So I still can't understand what the meaning of it.
print(numbers) //[20, 19, 1, 12]
let sortedNumbers = numbers.sort { $0 > $1 }
print(sortedNumbers) //[20, 19, 12, 1]
Can someone explain this simple piece of code above for me? Like how this simple code $0 > $1 implement the sort function, sorting the numbers from big to small.
I know some about index, and this $0 looks like index, but it only has $0 and $1 two indices. So how can it be used into 4 numbers? According to my knowledge in C++ before, I can't understand the principle in this.
Please make your answer as specific as possible. Thank you!
----------------- Below is edited extra part -------------------
I don't know whether stackoverflow would allow me to edit my question like this, but this extra part is too long, so I can't add it in the comment.
#pbodsk #Paul Richter
So the sort() syntax in swift uses quick sort to deal with sort function?
Actually my question is more about "what is the operating principle of sort{$0 > $1}". I know what you mean above, and I think it's similar with what swift 2.1 document says, but your answer is not what I really want to know. Sorry, my English expression is not very good. Let me try another way.
When I learnt C++ before, there are always some documents to explain what a function's operating principle is or how this function (like sort() here) operate in background. Sort() here needs to compare first and second interchange. In C++, it's like
if numbers[1] < numbers[2]{ //just consider this pseudocode
int k;
k = numbers[1];
numbers[1] = numbers[2];
numbers[2] = k;
}
We can see this process is obvious. In swift, it's like
numbers.sort({(val1: Int, val2: Int) -> Bool in
return val1 > val2
})
Where is it compared? And how is it interchanged? Does return val1 > val2 automatically compare and interchange these two values and return them? Just this one syntax implement these all 3 processes? How? This is what I really want to know. Sorry again for my poor English expression.
#the_UB and #moonvader are both right, but I just thought that I would extend the example from #moonvader a bit, just to show you how we end up with $0 > $1
If you look at the example in "The Swift Programming Language" about Closure Expressions you can see that to sort an array you call the sort method which can then take a function as a parameter.
This function must take two parameters and compare them, and then return a boolean.
So if we have this array:
let numbers = [4, 6, 8, 1, 3]
and this method
func sortBackwards(val1: Int, val2: Int) -> Bool {
print("val1: \(val1) - val2: \(val2)" )
return val1 > val2
}
We can sort the elements like so:
numbers.sort(sortBackwards) //gives us [8, 6, 4, 3, 1]
The sort method will use our sortBackwards method on each of the elements in the array and compare them.
Here's the output of the print
val1: 6 - val2: 4
val1: 8 - val2: 4
val1: 8 - val2: 6
val1: 1 - val2: 4
val1: 3 - val2: 1
val1: 3 - val2: 4
OK, let's reduce that.
Instead of defining a function, we can add that directly as a parameter to the sort method like so:
numbers.sort({(val1: Int, val2: Int) -> Bool in
return val1 > val2
})
And we still end up with [8, 6, 4, 3, 1] (how fortunate!)
OK, the next thing we can do is what in "The Swift Programming Language" (the link above) is called "Infering Type From Context". As we call this method on an array of Ints, Swift can figure out that our val1 and val2 parameters must be Ints too, there's no need for us to tell it. So, lets remove the types. That leaves us with:
numbers.sort({val1, val2 in
return val1 > val2
})
And still the same result.
OK, getting there. The next thing we can do is what in the book is called "Implicit Returns from Single-Expression Closures"
As our comparison can be done in one line there's no need for us to use return. So:
numbers.sort({val1, val2 in val1 > val2})
Still gives us [8, 6, 4, 3, 1]
Finally we're getting to what #moonvader used much much less words to explain :-) namely "Shorthand Argument Names"
As it says in the book:
Swift automatically provides shorthand argument names to inline closures, which can be used to refer to the values of the closure’s arguments by the names $0, $1, $2, and so on.
So, in our example, val1 can be replaced by $0 and val2 can be replaced by $1
Which gives us:
numbers.sort({$0 > $1})
And still we get [8, 6, 4, 3, 1]
We can then continue to use a "Trailing Closure", which means that if the last parameter of a function is a closure, we can add that parameter "outside" the function.
So we end up with:
numbers.sort{$0 > $1}
And the outcome is still [8, 6, 4, 3, 1]
Hope that helps to clarify things.
Here is what all need to know: Sort and Sorted.
To be more specific, Sorting can be two type : Ascending and Descending.
Q - So to do sorting, what do we need?
A - We need two variables to hold two variable(I don't know if it is the correct word)
Hence in this case we have two variable $0 and $1. These both are shorthands to represent left and right variable. Both will help to sort.
">" will do descending.
"<" will do ascending.
From developer.apple.com
Shorthand Argument Names
Swift automatically provides shorthand argument names to inline closures, which can be used to refer to the values of the closure’s arguments by the names $0, $1, $2, and so on.
If you use these shorthand argument names within your closure expression, you can omit the closure’s argument list from its definition, and the number and type of the shorthand argument names will be inferred from the expected function type. The in keyword can also be omitted, because the closure expression is made up entirely of its body:
reversed = names.sort( { $0 > $1 } )
Here, $0 and $1 refer to the closure’s first and second String arguments.
The process of sorting a list consists of repeatedly reordering its elements until nothing remains to be reordered. Now there are many sorting algorithms, but they all do this, in different ways. So then how are elements reordered? By comparing two given elements, and deciding which comes first, and swapping them if needed.
We can separate the overall reordering and swapping parts from the comparison part, and write a sort function that will take care of all the repeated reordering stuff, and just require the caller to specify how to compare two elements. If the list consists of numbers, it's almost always the case that the way to compare them is to just take their value. But suppose the list consists of things a little more complicated, like cars. How do you compare two cars? Well, you could compare them by numerically comparing their top speed. Or their gas mileage. Or price.
But the comparison doesn't have to be numerical. We could compare two cars by actually racing them. We could compare two cars by just saying if one is blue and the other isn't, the blue one is ordered first, and if neither or both are blue they are ordered as they already are.
We could come up with all sorts of ways to compare two cars. And the sorting algorithm could then sort a list of cars, without knowing anything about cars, as long as we the caller just tell it how to compare cars - any two given cars. We just have to express that comparison as an expression that returns a boolean, where if it's true, the first car is ordered before the second one, and if it's false, the first car is ordered after the second one.
Returning to numbers, that's what sort { $0 > $1 } means, in Swift's very concise syntax: "Sort, where if the first element is > the second one, order the first one before the second one."
You asked how it can sort four numbers with only two indices. $0 and $1 are not bound to the four specific elements in the list [20, 19, 1, 12], they are bound to any two given numbers that need to be compared, because the sorting algorithm repeately needs to do this.
There are a few things to note. First, the operator > has to be defined for the kinds of elements you are sorting. In the example the elements are numbers, and > is indeed defined. Second, the sort function specifies that the boolean true orders the first one before the second rather than the other way around, so the comparison function follows that specification. Third, the last evaluated expression is taken as the boolean value to be used. Having these two assumptions beforehand allows the comparison function to be written so concisely.
So if we wanted to sort those cars by racing them, we could write it like this:
cars.sort {
winner_of_race_between($0, $1) == $0
// if the first car beats the second, it is sorted ahead
}
Or exclusive blueness:
cars.sort { //not guaranteed to be valid Swift, just consider this pseudocode
if(($0.color != Color.blue) && ($1.color == Color.blue) {
$1
} else if (($0.color == Color.blue) && ($1.color != Color.blue)) {
$0
} else { //leave them in same order
$0
}
}
extension Array {
public func mySorted(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> [Element] {
var newArray: [Element] = self
if newArray.count <= 1 {
/// nothing to do
} else if newArray.count <= 32 { /// 32 ?? 64
for l in 1..<count {
for r in (0..<l).reversed() {
if try areInIncreasingOrder(newArray[r + 1], newArray[r]) {
(newArray[r + 1], newArray[r]) = (newArray[r], newArray[r + 1])
} else {
break
}
}
}
} else {
/// others sort
}
return newArray
}
}
var array: [Int] = [4, 6, 8, 1, 3]
let a1 = array.sorted {
print("\($0) \($1)")
return $0 > $1
}
print("---------")
let a2 = array.mySorted {
print("\($0) \($1)")
return $0 > $1
}
print("==========")
let a1 = array.sorted {
print("\($0) \($1)")
return $0 < $1
}
print("+++++++")
let a2 = array.mySorted {
print("\($0) \($1)")
return $0 < $1
}