List 如何使用Applescript查找列表中最大值的索引?

List 如何使用Applescript查找列表中最大值的索引?,list,indexing,applescript,List,Indexing,Applescript,我有一个int列表,如{18,18,18,18,22,21},我想使用Applescript获取此列表的最大值,并获取最大索引,请教我这有两个阶段: 确定列表中的最大值 已知最大值后,确定该值在列表中最后一次出现的索引 我将使用我在下面演示的示例中生成的示例列表。但是,您可以简单地用您的列表替换我的列表,所描述的过程也同样有效,并产生特定于您输入的结果 1.检索数字列表中的最大值 获取列表中最大值的一种快速而肮脏的方法是使用bash numericsort命令,然后选择最后一项: set

我有一个int列表,如{18,18,18,18,22,21},我想使用Applescript获取此列表的最大值,并获取最大索引,请教我这有两个阶段:

  • 确定列表中的最大值
  • 已知最大值后,确定该值在列表中最后一次出现的索引
  • 我将使用我在下面演示的示例中生成的示例列表。但是,您可以简单地用您的列表替换我的列表,所描述的过程也同样有效,并产生特定于您输入的结果

    1.检索数字列表中的最大值 获取列表中最大值的一种快速而肮脏的方法是使用bash numeric
    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.确定列表中给定项的索引 暂且不考虑最大值,问题的后半部分涉及到能够确定任何给定项在有序列表中的位置

    最明显的解决方案是,与前面一样,迭代列表中的每个项目并执行此操作:

    • 如果当前项等于目标项,则将其索引附加到为存储匹配索引而保留的列表的末尾
    到达列表末尾后,匹配索引列表将包含其值等于目标项目值的项目的所有位置;或者匹配的索引列表将是一个空列表,表示主列表不包含我们找到的值

    AppleScript列表中第一项的索引为
    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}