【问题标题】:Applescript compare items in the same arrayApplescript 比较同一数组中的项目
【发布时间】:2018-10-10 11:35:35
【问题描述】:

我有这份清单

set myList to {{1, "Bob"}, {1.5, "Jane"}, {3, "Joe"}, {1, "Jack"}}

repeat with a in myList
    --something like that a+
    if item 1 of a is equal to item 1 of a+ then
        --create list 
    end if
end repeat

有没有办法根据它们的第一个属性来比较项目?我想将第一项相同的所有项目添加到列表中

【问题讨论】:

    标签: arrays list object applescript


    【解决方案1】:

    这是一种方法,如果您有非常大的列表,这也是一种非常有效的方法:

    to filterItems from (L as list) ¬
        into |L*| as list : null ¬
        thru filter as handler
        local L, |L*|, filter
        
        if |L*| = null then set |L*| to {}
        
        script filteredItems
            property array : L
            property fn : filter
            property list : |L*|
        end script
        
        tell the filteredItems to repeat with x in its array
            if fn(x) = true then set ¬
                end of its list ¬
                to x's contents
        end repeat
        
        return the list of filteredItems
    end filterItems
    

    这个函数(处理程序),顾名思义,接受一个列表并根据某些标准对其进行过滤。然后,它可以选择将过滤后的项目存储在一个新列表中,您可以将其传递给要填充的处理程序;或者您可以允许处理程序将过滤后的列表作为结果返回,然后将其分配给新变量。

    过滤器由您定义的另一个处理程序提供。这是一个作用于列表中每个元素的函数,返回 truefalse,具体取决于它是否通过了您定义的某些测试。

    在您的特定情况下,您希望它通过的测试是每个项目的第一个元素是一个特定值,例如1. 这样,您最终会得到一个过滤列表,其中包含匹配第一个元素的项目。

    此过滤器的处理程序如下所示:

    on firstItemEquals1(x)
        item 1 of x = 1
    end firstItemEquals1
    

    一个简单的单行测试,确保每个项目的第一个元素是 1。

    然后,当您运行以下行时:

    filterItems from myList thru firstItemEquals1
    

    结果是这样的:

    {{1, "Bob"}, {1, "Jack"}}
    

    相反,我们可以定义另一个过滤器处理程序,它只挑选出其第一个元素是奇数的那些项目;或者它的第二个元素以字母“J”开头:

    on firstItemIsOdd(x)
        (item 1 of x) mod 2 = 1
    end firstItemIsOdd
    
    
    on secondItemStartsWithJ(x)
        item 2 of x starts with "J"
    end secondItemStartsWithJ
    

    然后:

    filterItems from myList thru firstItemIsOdd
        --> {{1, "Bob"}, {3, "Joe"}, {1, "Jack"}}
    
    
    filterItems from myList thru secondItemStartsWithJ
        --> {{1.5, "Jane"}, {3, "Joe"}, {1, "Jack"}}
    

    编辑:处理多个类似案例

    如果我有很多重复的第一个值怎么办?我必须为它们中的每一个创建处理程序?

    不,但我们必须对 filterItems 处理程序进行轻微调整,并创建另一个与之一起工作的处理程序,这将允许我们使用嵌套函数重复执行繁重的任务,而无需为每个任务。

    to filterItems from (L as list) ¬
        into |L*| as list : null ¬
        thru filter
        local L, |L*|, filter
        
        if |L*| = null then set |L*| to {}
        
        script itemsToBeFiltered
            property array : L
        end script
        script filteredItems
            property list : |L*|
        end script
        
        repeat with x in the array of itemsToBeFiltered
            tell wrapper(filter) to if fn(x) = true ¬
                then set end of filteredItems's list ¬
                to contents of x
        end repeat
        
        return the list of filteredItems
    end filterItems
    

    意义的主要变化是引入tell wrapper(filter) 行。我们正在引入一个辅助函数来将我们的过滤器处理程序嵌套在脚本对象中。 wrapper 函数如下所示:

    on wrapper(function)
        if function's class = script then return function
        
        script
            property fn : function
        end script
    end wrapper
    

    现在,我们可以定义如下所示的过滤器处理程序:

    on firstItemEquals(N)
        script
            on fn(x)
                item 1 of x = N
            end fn
        end script
    end firstItemEquals
    

    这个新版本的处理程序允许我们选择与列表中每个项目的第一个元素进行比较的值。这样,我们就不需要编写单独的处理程序;我们可以这样做:

    filterItems from myList thru firstItemEquals(1)
        --> {{1, "Bob"}, {1, "Jack"}}
    

    然后是这个:

    filterItems from myList thru firstItemEquals(3)
        --> {{3, "Joe"}}
    

    【讨论】:

    • 非常有用!但是如果我有很多重复的第一个值怎么办?我必须为它们中的每一个创建处理程序
    • @Spy 我已更新答案以解决您的问题。对不起,我花了一段时间,我必须弄清楚如何去做。我知道这是可能的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多