The original name, sortedPrefix, already had all the consistency needed. It was consistent with both the general sense of sorting, rather than any notion of min or max, as conveyed by sorted; and that you were receiving a prefix (which would be an indicator it was doing a partial sort, if you were familiar with the advantages there), consistent with the prefix method. So while min or max may be consistent in that there are other methods already named min or max, they don't actually describe the action being taken and so are generally inferior names.
As I noted above, sortedPrefix unfortunately sounds too much like you're just sorting the prefix. Even though the names min(count:) and max(count:) don't describe the action, they do describe the result, which is okay too.
That's correct â we'll include both those unconstrained methods and the simpler versions for collections of Comparable elements.
That was my initial feeling as well but I quickly overcame it when I realized it was a compound of sorted and prefix rather than its own thing. Trying to name things assuming a zero knowledge user isn't going to end well. There are few names that meet that criteria. To my mind, the risk of thinking you're sorting a prefix (despite the words being in the opposite order, and documentation) is far lower than the continual cognitive burden of applying min and max to arbitrary predicates. They're useful shortcuts for the right kinds of data but aren't generally applicable. Min and max just aren't good terms for this feature in general.
I'm fine with the names of min(count:), max(count:), and their unconstrained min(count:by:) and max(count:by:) counterparts. ![]()
I agree with others that sortedPrefix is ambiguous. I always thought the ambiguity is easily solved by realising the unintended meaning makes no sense to exist as a function of its own.
But that's ambiguity anyway.
I think the only slight downside with the min/max naming (and which sortedPrefix, or sortedSuffix for the matter wouldn't suffer) is it's not perfectly clear from their name in what order the result will be. Especially for max(count:[by:]), why doesn't its return value contain elements in descending order like "the greatest N" commonly*)? Or should it?
But this is easily documented I think.
*) E.g. In Python, heapq.nlargest(3, [8, 4, 6, 2, 3, 5, 1, 7]) returns [8, 7, 6], not [6, 7, 8].
One potential issue I see with the min/max separation is that if the comparison has distinguishable equivalent elements then min should prefer the earlier elements and max should prefer the later elements:
// e.g. given:
let a = [(0, 1), (0, 2), (0, 3), (0, 4), (0, 5)]
// then:
a.min(count: 3) { $0.0 < $1.0 } // [(0, 1), (0, 2), (0, 3)]
a.max(count: 3) { $0.0 < $1.0 } // [(0, 3), (0, 4), (0, 5)]
I think I'm struggling to understand what the cognitive burden is here. What is your internal definition of the minimum element that doesn't naturally apply when using an arbitrary ordering predicate?
I love it!
I disagree that least and smallest don't make sense in this context though: they're literally the English equivalent of Latin minimum (minima), and as someone has pointed out already, Python types have the function nsmallest and nlargest.
But min(count:) and max(count:) is by far the clearest description of this function that I've seen proposed thus far, and very nicely eliminates the ambiguity caused by sortedPrefix.
This can be addressed, I think, by naming the function max(count:sortedBy:).
With arbitrary predicates you can sort by anything, including things that don't naturally have a min or max. If I sort an array of User values by a combination of their properties, what does min or max mean? If they really just mean first or last, then that's what the name should be.
I'm not sure how the obscure etymology of these words helps users understand what these methods do. But at least min and max are somewhat understandable, as long as you assume the min of some sort are the first elements and the max are the last, but largest and smallest are even worse. Using those are completely wrong for nearly all elements, since a predicate doesn't say anything about relative size.
If prefix isn't considered clear, then it seem first(count:by:) and last(count:by:) would be better. Pretty much all of the positives of min and max with none of the negatives.
I still think sortedPrefix is the best name here since it most closely reflects what's going on, since the algorithmic optimization actually being performed is prefix sorting.
This is a ship that's already sailed.
FWIW, I think of sorting as ordering things from smallest to largest, not from first to last. The latter refers to the order of elements relative to each other in an actual collection instance. But we are looking for the smallest or largest elements by some criteria regardless of their position in this or any other actual collection.
The standard library uses prefix for the first n, so I don't see what's gained here by avoiding that word and replacing it with first: that doesn't address the problem being tackled here. There's nothing wrong with something like prefix(_:afterSortingBy:), but it doesn't provide a basis for naming the corresponding method without a custom predicate.
There is broad consensus that sortedPrefix is ambiguous, and stating that it's the best name doesn't make that ambiguity go away, so let's get on with working to improve it.
It avoids the ambiguity some feel with sortedPrefix while still connoting relative position rather than size or value like min/max or smallest/largest. Unfortunately, only prefix and suffix currently take a count, so either usage will be unprecedented and won't benefit from consistency with current APIs.
Broad being relative here. It's not as if the general Swift community has used these APIs, so we really have no idea how popular any sort of ambiguity really is, or how difficult it would be for people to understand the true meaning. I am surprised Algorithms is being so aggressive in renaming things without much usage.
The name can't be first or last because they mean something else already for a collection, and they would only make sense as some phrase like wouldBefirstAfterSorting.
What do you mean by âdon't naturally have a min or maxâ? Do you mean that User doesn't currently conform to Comparable? min and max are defined using the comparison predicate, whether that is supplied explicitly as a closure or comes from Comparable performance, and they mean the same thing either way.
By that logic the name can't be min or max, since they already mean something else for a collection too. But you're right, the version with a defaulted predicate would just look like first(5), which certainly doesn't look like a sort. So firstSorted/lastSorted. Or perhaps partiallySortedFirst/partiallySortedLast. Ultimately, I still think it's important to indicate this is a sort, even a partial sort, to properly reflect what's going on.
No, it wouldn't conform to Comparable since there's no single way to make Users Comparable, hence the use of custom predicates. Likely there are many, equally valid orderings of Users for any given application. In the end, I just don't think it makes sense to refer to a "minimum User" or a "maximum User", so I don't think min / max names are generally applicable. If I need to get the first five Users by first name I'm not going to think about getting the minimum Users. I'm going to think about getting the first five elements of a collection of Users when sorted by first name.
I agree that there can be many desirable ways to sort any type, so the functions take a comparison predicate. These functions do give the minimum/maximum elements according to the given comparison predicate though, in the same way that a collection can be sorted according to an arbitrary comparison predicate (even if the type conforms to Comparable in a different way). So I find them generally applicable in the same sense, personally, and your two thoughts seem equivalent to me.
The benefit I see with something like firstSorted(count:) and lastSorted(count:) is that it is clear that the results of both will be in ascending order:
numbers.lastSorted(count: 5) // [96, 97, 98, 99, 100]
With min(count:) and max(count:) I would intuitively expect the results of the latter to be in descending order:
numbers.max(count: 5) // Expected: [100, 99, 98, 97, 96], actual: [96, 97, 98, 99, 100]
That can of course be worked around with documentation, but it would be working against my intuition at least.
firstSorted and lastSorted seem to have exactly the same problem as sortedPrefix, i.e. it's ambiguous if you're sorting it and taking the first n, or taking the first n and sorting them. The words are just in the opposite order, which might actually be more confusing, and it uses a non-standard term for for the first n, which should be called the prefix.
Or, it could just return the values in the order you expect, and users who want the other order can reverse it. ![]()
At the risk of making the method names increasingly long, would there be any ambiguity left in this name?
func firstAfterSorting(count: Int) -> [Self]
func firstAfterSorting(count: Int, by: (Self, Self) -> Bool) -> [Self]
Probably not, other that implying that the sorting is always actually done and thus being somewhat misleading about the complexity. It should be prefixAfterSorting though, because that's what first with a count is called in the standard library. It functionally means the same thing as min, so I'm not sure the verbosity is justified.
Maybe prefixWhenSorting wouldnât give this impression as much (at least thatâs how it works for me). I like the fact that itâs more explicit than min, but I donât find it very pretty.
I think that, like others here, I would be ok with min(count:).