The closure’s arguments $0 is not $0, but $1

Copy the example from the document and paste the result below too.
Don’t know why $0 is not 20, but 19.

Build it on Xcode v10.2.1.

—— snip ——

var numbers = [20, 19, 7, 12]

let sortedNumbers = numbers.sorted { print(“$0 = ($0), $1 = ($1)")

**return** $0 > $1 }

print(sortedNumbers)

Cleaned-up snippet

let numbers = [20, 19, 7, 12]
let sortedNumbers = numbers.sorted {
    print("$0 = \($0), $1 = \($1)")
    return $0 > $1
}

You're assuming that sorted somewhere call the function like this

func sort(...) {
    ...
   areInIncreasingOrder(firstElement, secondElement)
    ...
}

which may not at all be true. sorted may call it in any manner it'd like, so long as it could produce a sorted list in the end.

May I ask what you're trying to do?

Also:

Which document are you referring to?

1 Like

Lantua via Swift Forums swift@discoursemail.com 於 2019年5月11日 04:55 寫道:


Lantua

    May 10

Cleaned-up snippet

    let numbers = [20, 19, 7, 12]
let sortedNumbers = numbers.sorted {
print("$0 = \($0), $1 = \($1)")
return $0 > $1
}

You're assuming that sorted somewhere call the function like this

    func sort(...) {
...
areInIncreasingOrder(firstElement, secondElement)
...
}

which may not at all be true. sorted may call it in any manner it'd like, so long as it could produce a sorted list in the end.

May I ask what you're trying to do?

Also:

Mike_Chen:
Copy the example from the document and paste the result below too.

Which document are you referring to?

Refer to Function and closure part of https://docs.swift.org/swift-book/GuidedTour/GuidedTour.html.

The first and second arguments should be 20 and 19. I expect they are $0=20 and $1=19, but they aren’t.

The first argument $0 is 19 and the second $1 is 20.

You shouldn't expect any particular order for comparisons when passing a closure as a predicate to a sorting function.

When you pass the closure to sort or sorted, it uses the closure as a tool to determine in which order two values should be. What values the closure receive is an implementation detail of how the code in the sort function works. There should be no expectation about any particular order because the exact sort algorithm used is not documented.

As an example, here is very simple algorithm for sorting:

extension Array {
	mutating func naiveSort(by isOrderedBefore: (Element, Element) -> Bool) {
		var allSorted = count < 2 // already sorted if zero or one element
		while !allSorted {
			allSorted = true // assume true until proven otherwise
			for index in 1 ..< count {
				if isOrderedBefore(self[index], self[index-1]) {
					swapAt(index, index-1)
					allSorted = false // need to recheck!
				}
			}
		}
	}
}

var numbers = [20, 19, 7, 12]
numbers.naiveSort {
	print("$0 = \($0), $1 = \($1)")
	return $0 > $1
}
print(numbers)

This algorithm is a bit dumb and will call the closure more often than the one in the standard library. But if you step through it, it should make it easier to understand why your closure is called with values in various order. Sorting is simply the process of calling the closure repeatedly on all the values until everything is properly ordered.

1 Like

The sort algorithm used, and therefore the order in which elements are compared, is an implementation detail of sorted; therefore, it may change from version to version, machine to machine, or even run to run.

1 Like

To put a name on it: that's bubble sort.

2 Likes

After proceeding to verify the result, the arguments take place the same disorder situation. The method only guarantee the result is correct, but the processing will not be compliance with the rule as expected. That’s totally what I can understand it now.

Yes. Perhaps it depends on machine memory alignment.

I think there's a bit of a language barrier here. There is no rule as to which elements a sort predicate will be invoked with, and certainly no rule as to the order. It is not out of compliance, because there's no rule to comply with.

1 Like