List 如何使用Applescript查找列表中最大值的索引?
我有一个int列表,如{18,18,18,18,22,21},我想使用Applescript获取此列表的最大值,并获取最大索引,请教我这有两个阶段:List 如何使用Applescript查找列表中最大值的索引?,list,indexing,applescript,List,Indexing,Applescript,我有一个int列表,如{18,18,18,18,22,21},我想使用Applescript获取此列表的最大值,并获取最大索引,请教我这有两个阶段: 确定列表中的最大值 已知最大值后,确定该值在列表中最后一次出现的索引 我将使用我在下面演示的示例中生成的示例列表。但是,您可以简单地用您的列表替换我的列表,所描述的过程也同样有效,并产生特定于您输入的结果 1.检索数字列表中的最大值 获取列表中最大值的一种快速而肮脏的方法是使用bash numericsort命令,然后选择最后一项: set
sort
命令,然后选择最后一项:
set L to {4, 24, 78, 32, 1.5, 32, 78, 4, 19, 78}
set text item delimiters to linefeed
do shell script "sort -n <<<" & quoted form of (L as text) & "| tail -n 1"
--> 78
2.确定列表中给定项的索引
暂且不考虑最大值,问题的后半部分涉及到能够确定任何给定项在有序列表中的位置
最明显的解决方案是,与前面一样,迭代列表中的每个项目并执行此操作:
- 如果当前项等于目标项,则将其索引附加到为存储匹配索引而保留的列表的末尾
1
。使用列表的length
属性获取整个列表中的项目数
下面是一个基本的应用程序脚本:
set L to {4, 24, 78, 32, 1.5, 32, 78, 4, 19, 78}
set matches to {}
set target to 78
repeat with i from 1 to L's length
if item i of L = the target then set end of matches to i
end repeat
return the matches
--> {3, 7, 10}
3.组合工艺
将问题的这两部分结合起来非常简单,只需按顺序运行每一半,注意使用过程前半部分的结果(最大值)作为列表中要查找的目标值:
set L to {4, 24, 78, 32, 1.5, 32, 78, 4, 19, 78}
set max to L's first item
# Get maximum value
repeat with x in L
if x > max then set max to x's contents
end repeat
set matches to {}
set target to max
# Get index of maximum value
repeat with i from 1 to L's length
if item i of L = the target then set end of matches to i
end repeat
return the matches
--> {3, 7, 10}
最后,由于您只需要最大索引,因此这只是匹配项
列表中的最后一个值,即10
,您可以通过替换返回匹配项
来获得该值:
return the last item in matches
--> 10
4.提高效率
概述了每个过程中的基本方法后,这些方法不一定是最快的方法。由于列表只包含10项,效率低下不是一个值得关注的问题。如果您有一个包含10000项的列表,那么您希望能够缩短获得结果的时间
我认为我正确地指出,在算法改进方面,没有明显的方法可以加快第一个过程:检索最大值需要比较每个项目的大小并保留最大值
但是,由于我们只需要确定列表中某个项目的最后一次出现,因此可以加快确定索引的速度
因此,我们可以像以前一样运行该流程,但需要做两个更改:
set L to {4, 24, 78, 32, 1.5, 32, 78, 4, 19, 78}
set max to L's first item
# Get maximum value
repeat with x in L
if x > max then set max to x's contents
end repeat
set target to max
# Get index of maximum value
repeat with i from L's length to 1 by -1
if item i of L = the target then exit repeat
end repeat
return i
--> 10
注意这里的第二个repeat
循环现在从最高索引向下运行到1
;而且,我们不再需要matches
列表,因此我们只需在找到匹配项时退出循环,然后查看i
的值
这里对算法的进一步改进是测试null情况,以确定我们是否真的需要遍历列表:null情况是列表不包含我们寻求的值的情况。AppleScript提供了一种内置的方法来检查这一点:
if the target is not in L then return 0
这一行将紧跟在将target设置为max
之后,紧跟在之前,用i.
重复
5.先进的改进 另一种提高效率的方法是,在解决算法本身的效率问题之后,解决脚本编写方式的效率问题。这比您现在需要关注的更高级,但如果我编写脚本供自己使用,我可能会实现以下算法: 我将定义一个名为
max()
的处理程序,该处理程序将列表作为其参数并返回最大值,我将实现此处理程序的脚本,如下所示:
on maximum(L as list)
local L
if L is {} then return {}
if L's length = 1 then return L's first item
script Array
property x0 : L's first item
property xN : rest of L
property fn : maximum(xN)
property predicate : x0 > fn
end script
tell the Array
if its predicate is true then return its x0
its fn
end tell
end maximum
这使用了一种称为脚本对象的东西来处理列表中的项目,这在AppleScript中比传统的迭代重复
循环快得多
接下来,我将定义另一个名为lastIndexOf()
的处理程序,该处理程序将提供的值和列表作为其两个参数,并返回给定列表中提供的值出现的最高索引。我的处理程序如下所示:
on lastIndexOf(x, L as list)
local x, L
if x is not in L then return 0
if L = {} then return
script Array
property x0 : L's last item
property xN : reverse of rest of reverse of L
property predicate : x0 ≠ x
end script
# For the last match only:
if Array's predicate is false then return (Array's xN's length) + 1
# For a match list (comment out line above):
tell the Array
if its predicate is false then ¬
return the lastIndexOf(x, its xN) ¬
& (its xN's length) + 1
return lastIndexOf(x, its xN)
end tell
end lastIndexOf
那么,我需要做的就是得到结果:
set L to {4, 24, 78, 32, 1.5, 32, 78, 14, 19, 78}
get the lastIndexOf(maximum(L), L)
--> 10
但是,不要试图理解我刚才在这里所做的工作,而要集中精力理解repeat
循环算法
为了完整起见,我加入了这些更高级的版本,读者可能会想,如果我把这个遗漏了,为什么我没有提供我所能提供的最佳解决方案
虽然在这些高级版本中使用的算法保持不变(看起来不像,但确实如此),但代码的编写方式使这些算法对于大型项目列表非常有效
但是,请注意,我没有包含任何错误处理,因此,如果要向这些处理程序传递包含非数字项的列表,其中至少有一个会抱怨。这有两个阶段:
set L to {4, 24, 78, 32, 1.5, 32, 78, 14, 19, 78}
get the lastIndexOf(maximum(L), L)
--> 10
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
use framework "Foundation"
set numberList to {18, 18, 18, 18, 22, 21, 22}
set nsNumberList to current application's NSArray's arrayWithArray:numberList
set maxValue to nsNumberList's valueForKeyPath:"@max.intValue") as integer -- 22
set maxIndex to ((nsNumberList's indexOfObject:maxValue) as integer) + 1 -- AppleScript's lists are 1-based
set maxIndexes to {}
repeat with i from 0 to (count numberList) - 1 -- Cocoa's lists are 0-based
if (maxValue's isEqualToNumber:(nsNumberList's objectAtIndex:i)) then
set end of maxIndexes to i + 1
end if
end repeat
maxIndexes -- {5, 7}