问题
Basically I just need help with finding the max of this code.
set numberList to {3, 4, 5, 6, 7, 8, 9, 10}
set max to numberList
repeat with x in numberList
if x > max then set max to x
end repeat
display dialog max
The error that I am getting is:
"Can’t make {3, 4, 5, 6, 7, 8, 9, 10} into type number." number -1700 from {3, 4, 5, 6, 7, 8, 9, 10} to number
回答1:
I'm glad @vadian
went for the AppleScriptObjC method, because it allows me to geek out on doing it the vanilla AppleScript way, just like you tried (and came very close to achieving). Let me show you how close you were. Here's your script, where I'm just switching out an identifier because I like denoting a generic list of stuff by L
, and will do this consistently in the various improvements that will follow on from this initial naive algorithm.
Also, let's make the list a bit more interesting than a sequence of numbers with increasing size.
I've labelled problem lines with a number that refers to footnotes immediately following:
set L to {6, 3, 7, 9, 4, 10, 2, 10, 8, 2}
set max to L --(1)
repeat with x in L
if x > max then set max to x
end repeat
display dialog max --(2)
¹ Settingmax
to the initial list,L
is an idea we'll look at later, but won't work here because it's not possible to compare a number to a list of numbers and tell me which of the two has a greater numeric value ? Therefore, you want your initial value ofmax
to be a number, but it can't be a number that is, itself, greater than the maximum value contained by your list, which is why the common mistake of thinking 0 is a suitable initial value will catch you out (consider a list of negative numbers): the only set of values that I could not create a list (of any length) that guarantees this algorithm to return the incorrect result is any subset of whatever list the algorithm operates upon. In other words, choose any value from the listL
.
² Get away from the novice's inclination to visualise results in dialog boxes. You'll be thankful you did. Instead, use the Results (or, even more useful, the Replies) pane at the bottom of your Script Editor window. If you're using Script Debugger, it's the one oversight that their events panel and their results panel tried so hard to improve on, but sometimes simpler is better.
And now the working version:
set L to {6, 3, 7, 9, 4, 10, 2, 10, 8, 2}
set max to some item in L
repeat with x in L
if x > max then set max to x's contents
end repeat
return max
I spent a lot of time as a teenager with no friends learning the joys of what can be done by grouping things together in lists. In mathematics, lists are called sets, and there's a field of study called Set Theory, which it turns out can be used exclusively to define every mathematical principle that exists or ever will exist. That's how amazing lists are.
Finding the maximum value in a list is one of the first, and incredibly important things one either learns about or discovers for themselves. It's a type of mapping that operates on a set, picking out the largest element, which is fundamental to defining a number system that now has a means of putting numbers in order. I first wrote such a procedure in Pascal, which I've since written in a dozen other languages, but AppleScript is so much more fun to do this with than in some other languages, because you can get it to do things that it probably wasn't meant to be able to do but somehow does. AppleScript lists are also an odd construct, as they are recursively, and infinitely, self-referential, which turns out is an interestingly property.
I won't explore what referenced values are, but it's why my script refers to x's contents
rather than just x
(thanks @vadian
), as contents
is what dereferences (i.e. evaluates) a referenced item. (Don't worry about it for now, but learn about it later on, as it can be a very useful concept to make use of if you know how).
It's also amusing that, unless dealing with lists that are really big, vanilla AppleScript typically out-performs AppleScriptObjC speedwise, which initially suffers with the extra overhead incurred from bridging to Objective-C. The cost eventually gets recuperated when dealing with hundreds or thousands of items per list, which AppleScriptObjC will, without question, wipe the floor with AppleScript in a speed test. But for many everyday situations handling lists with under a hundred items, the tortoise beats the hare quite unexpectedly and satisfyingly, but you need to know how to structure your script to get it to do this.
So... The rest of what will follow is for educational fun...
I'll start by taking your initial idea of setting max
to the initial list, and perform a process on this list over and over that ends up getting us the maximum value. But I'm not going to bother to define a separate max
variable, as we can just perform the process on the original list, L
. Take a look at this slight variation on your initial technique:
set L to {6, 3, 7, 9, 4, 10, 2, 10, 8, 2}
repeat while L's length > 1
if L's first item > L's last item then set ¬
L's last item to L's first item
set L to the rest of L
end repeat
return L's first item
There are two properties of any list
in AppleScript that the above script makes use of: length
tells use how many items the list contains; and rest
is all but the first item in the list.
In this method, we compare the item at position 1 to the item at the last position. The winner (the largest value) gets to sit in the last position. Then the list
is shortened (or reduced) by getting the rest of...
it, which removes the first item is each time until we're left with just a one-item list. That item will be survivor from the original list and so that's our maximum value that we retrieve and return.
This technique is a basic implementation of a process to reduce
or fold a list bit by bit, often acting to reduce the complexity of a list (but it doesn't have to), so that you start with an object composed of many items that might be structured in a complex way, but after repeated folding, what you're most often left with is a simpler object, like a single, unary value such as a number.
It might not appear so, but this is a really powerful technique that can form the basis of lots of other things we like to do with lists, such as counting the number of items it contains, or changing the items by using the same rules applied to each, e.g. doubling all items (this is a type of process called a map
), or removing all odd-valued items but keeping all even-valued ones (this is a filter
).
More to follow tomorrow...
来源:https://stackoverflow.com/questions/58938393/finding-the-max-in-applescript