AppleScript名:asoc_レコード内の計算(合計)v2 |
— Created 2014-11-19 by Takaaki Naganoya — 2014 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" set aCompanyRec to {employees:{{age:20, nameStr:"A"}, {age:23, nameStr:"B"}, {age:19, nameStr:"C"}}} set aDic to current application’s NSDictionary’s dictionaryWithDictionary:aCompanyRec set aveAge to (aDic’s valueForKeyPath:"employees.@sum.age") set aveAgeNum to aveAge as real –> 62.0 |
カテゴリー: list
指定リストの次元を取得する v3
任意のリスト(配列)変数の次元を取得するAppleScriptです。
手軽に多次元配列を宣言してアクセスできるAppleScriptですが、作成した配列変数の次元を確認する方法は用意されていません。
そこで、指定リスト(配列)の次元数を取得するものを書いてみました。
日常的に2次元配列とか3次元配列は使いますが、4次元配列まではあまり使ったことがありません。実用上は3次元配列ぐらいでしょうか。
たまに2次元配列が使えない言語とか、実用上は2次元配列ぐらいまでしか直接宣言できない言語があって驚かされます。
AppleScript名:指定リストの次元を取得する v3 |
use AppleScript version "2.4" use scripting additions set aList to {{1, 2, 3}, {4, 5, 6}} –2D List set aDim to getDimension given tArray:aList –> 2 set bList to {{{1, 2}, {2, 3}, {3, 4}}, {{1, 2}, {2, 3}, {3, 4}}, {{1, 2}, {2, 3}, {3, 4}}} –3D List set bDim to getDimension given tArray:bList –> 3 set cList to {1, 2, 3, 4, 5, 6} –1D List set cDim to getDimension given tArray:cList –> 1 set dList to {{{{1, 2}, {2, 3}}, {{1, 2}, {2, 3}}, {{1, 2}, {2, 3}}}} –4D List set dDim to getDimension given tArray:dList –> 4 –指定Listの次元を再帰で取得する on getDimension given tArray:aList as list : {}, curDim:aNum as integer : 1 set anItem to contents of first item of aList set aClass to class of anItem if aClass = list then set aNum to aNum + 1 set aRes to getDimension given tArray:anItem, curDim:aNum else return aNum end if end getDimension |
2D Listをユニーク化
AppleScript名:2D Listをユニーク化(asoc) |
— Created 2017-05-25 23:27:42 +0900 by Takaaki Naganoya — 2017 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" set aList to {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {64620, 537, 32893}, {64620, 537, 32893}, {64620, 537, 32893}, {64620, 537, 32893}} set bList to uniquifyList(aList) of me –> {{0, 0, 0}, {64620, 537, 32893}} on uniquifyList(aList as list) set aArray to current application’s NSArray’s arrayWithArray:aList set bArray to aArray’s valueForKeyPath:"@distinctUnionOfObjects.self" return bArray as list end uniquifyList |
1D Listをユニーク化 v2
AppleScript名:1D Listをユニーク化 v2 |
— Created 2014-11-25 by Takaaki Naganoya — 2014 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" –set aList to {{aName:"Apple", aNum:1}, {aName:"Orange", aNum:1}, {aName:"Apple", aNum:1}} set aList to {1, 1, 1, 3} set aRes to uniquify1DList(aList, true) –> {1, 10, 90, 100, 300} –1D/2D Listをユニーク化 on uniquify1DList(theList as list, aBool as boolean) set aArray to current application’s NSArray’s arrayWithArray:theList set bArray to aArray’s valueForKeyPath:"@distinctUnionOfObjects.self" if aBool = true then return bArray as list else return bArray end if end uniquify1DList |
listの項目をフィルタリング(項目文字長)
AppleScript名:listの項目をフィルタリング(項目文字長) |
— Created 2014-11-21 by Takaaki Naganoya — 2014 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" set aList to {"piyomaru", "Piyomaru Software", "Naganoya", "Takaaki", "MacBook Pro Retina mid 2012"} set bList to filterListUsingPredicate(aList, "length > 8") –文字列長が8文字より長い項目を返す –> {"MacBook Pro Retina mid 2012", "Piyomaru Software"} set cList to filterListUsingPredicate(aList, "SELF MATCHES ’.*e$’") –正規表現で末尾が"e" –> {"Piyomaru Software"} set dList to filterListUsingPredicate(aList, "SELF LIKE ’piyo*’") –> {"piyomaru"} set eList to filterListUsingPredicate(aList, "SELF LIKE[c] ’piyo*’") –> {"piyomaru", "Piyomaru Software"} set fList to filterListUsingPredicate(aList, "SELF CONTAINS[c] ’Piyo’") –> {"piyomaru", "Piyomaru Software"} on filterListUsingPredicate(aList as list, aPredicateStr as string) –ListからNSArrayへの型変換 set setKey to current application’s NSMutableSet’s setWithArray:aList –抽出 set aPredicate to current application’s NSPredicate’s predicateWithFormat:aPredicateStr set aRes to (setKey’s filteredSetUsingPredicate:aPredicate) set bRes to aRes’s allObjects() –NSArrayからListに型変換して返す set cRes to bRes as {list, list of string or string} return cRes end filterListUsingPredicate |
listの項目をフィルタリング(キーワードを含む)
AppleScript名:listの項目をフィルタリング(キーワードを含む) |
— Created 2014-11-21 by Takaaki Naganoya — 2014 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" use framework "ASObjCExtras" set aList to {"piyomaru", "Naganoya", "Takaaki", "MacBook Pro Retina mid 2012", "piyomarusoft"} set bList to filterListUsingPredicate(aList, "SELF contains[cd] %@", "Piyo") –部分一致 –> {"piyomaru", "piyomarusoft"} set cList to filterListUsingPredicate(aList, "SELF matches[cd] %@", "piyomaru") –完全一致 –> {"piyomaru"} set dList to filterListUsingPredicate(aList, "SELF like[c] %@", "*soft") –後方一致 –> {"piyomarusoft"} on filterListUsingPredicate(aList as list, aPredicateStr as string, targStr as string) set setKey to current application’s NSMutableSet’s setWithArray:aList set aPredicate to current application’s NSPredicate’s predicateWithFormat_(aPredicateStr, targStr) set aRes to (setKey’s filteredSetUsingPredicate:aPredicate) set bRes to aRes’s allObjects() set cRes to bRes as {list, list of string or string} return cRes end filterListUsingPredicate –2Dリストから、指定インデックスアイテムで、指定データが該当する最初のものを返す on searchInListByIndexItem(aList as list, itemNum as integer, hitData as string) –ListからNSMutableSetへの型変換 set setKey to current application’s NSMutableSet’s setWithArray:aList –Predicate Stringを組み立てる if itemNum < 1 then return {} set aPredicateStr to ("SELF[" & (itemNum – 1) as string) & "] == ’" & hitData & "’" –抽出 set aPredicate to current application’s NSPredicate’s predicateWithFormat:aPredicateStr set aRes to (setKey’s filteredSetUsingPredicate:aPredicate) set bRes to aRes’s allObjects() –NSArrayからListに型変換して返す set cRes to bRes as list if cRes is not equal to {} then set cRes to contents of first item of cRes end if return cRes end searchInListByIndexItem |
listをフィルターする(指定数以上の要素)
AppleScript名:listをフィルターする(指定数以上の要素) |
— Created 2014-12-28 by Takaaki Naganoya — 2014 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" set theArray to current application’s NSArray’s arrayWithArray:{8, 2, 7, 3, 9, 1, 6, 4} set thePred to current application’s NSPredicate’s predicateWithFormat:"self > 6" set bArray to (theArray’s filteredArrayUsingPredicate:thePred) as list –> {8, 7, 9} |
listをフィルターする(指定数以外の要素)
AppleScript名:listをフィルターする(指定数以外の要素) |
— Created 2014-12-28 by Takaaki Naganoya — 2014 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" set theArray to current application’s NSArray’s arrayWithArray:{8, 2, 7, 3, 9, 1, 6, 4} set thePred to current application’s NSPredicate’s predicateWithFormat:"(self != 2) AND (self != 4)" set bArray to (theArray’s filteredArrayUsingPredicate:thePred) as list –> {8, 7, 3, 9, 1, 6} |
listをフィルターする(指定文字ではじまる要素)
AppleScript名:listをフィルターする(指定文字ではじまる要素) |
— Created 2014-12-28 by Takaaki Naganoya — 2014 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" set stringArray to current application’s NSArray’s arrayWithArray:{"adobe", "Apple", "microsoft", "google"} set thePred to current application’s NSPredicate’s predicateWithFormat:"self BEGINSWITH ’a’" set bArray to (stringArray’s filteredArrayUsingPredicate:thePred) as list –> {"adobe"} |
2D listをフィルターする
AppleScript名:2D listをフィルターする |
— Created 2014-12-28 by Takaaki Naganoya — 2014 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" set theArray to current application’s NSArray’s arrayWithArray:{{8, 2}, {7, 3}, {9, 1}, {6, 4}, {10, 10}} set thePred to current application’s NSPredicate’s predicateWithFormat:"(self[0] >5) AND (self[1] > 3)" set bArray to (theArray’s filteredArrayUsingPredicate:thePred) as list –> {8, 7, 3, 9, 1, 6} |
入れ子のリストをフラット化v03
2次元や3次元の多次元リスト(多次元配列)を1次元配列化するAppleScriptです。
AppleScriptのリスト型変数(配列変数)は簡単に多次元配列を作れるものの、リスト内の要素の検索などはとくに処理系に用意されていないほか、多次元配列を1次元配列に変換する機能は用意されていません。
そのため、このルーチンを用いて変換しています。Cocoaの機能を呼び出すよりも高速に処理できるため、このまま使っています。AppleScriptの処理系においては、本ルーチンよりも高速に処理できるものは存在していません。
# データ量が増える(1万項目以上)と、Cocoaの機能を利用したもののほうが高速ですが、このFlattenListのようにイレギュラーな次元数の多次元配列を1次元配列化できるものは見かけたことがありません
多次元配列の中に指定要素が入っているかを確認する場合など、本ルーチンで1次元配列に変換してからis inで存在確認を行うことになります。
AppleScript名:入れ子のリストをフラット化v03 |
set aList to {{"item 1", "item 2", {"item 1", "item 2", "item 3"}}, {"item1", "item 2", "item 3"}, "item 3"} set aRes to FlattenList(aList) of me –> {"item 1", "item 2", "item 1", "item 2", "item 3", "item1", "item 2", "item 3", "item 3"} –By Paul Berkowitz –2009年1月27日 2:24:08:JST –Re: Flattening Nested Lists on FlattenList(aList) set oldDelims to AppleScript’s text item delimiters set AppleScript’s text item delimiters to {"????"} set aString to aList as text set aList to text items of aString set AppleScript’s text item delimiters to oldDelims return aList end FlattenList |
リストからフィールド内容を指定して抽出
リスト(配列)に入れたレコードから、属性値ラベルと値を指定してしぼりこみを行うAppleScriptです。
{{label1:"data", label2:"data", label3:"data"},{label1:"XXXX", label2:"YYYYY", label3:"ZZZZ"}}
このようなデータの絞り込みは、従来はDatabase Events(macOS標準搭載のSQLiteラッパー、AppleScriptのフィルタ参照でデータの絞り込みを行う専用ツール)を利用したり、サードパーティのデータベースアプリケーションを併用する必要があったわけですが、前者はデータベースファイルを作成する必要があり、後者は購入する必要がありました。
# データベースファイルの作成をScripterに意識させない作りになっていれば、もう少し使い勝手がよかったはずですし、サンプルScriptが希少すぎ。海外の技術誌のバックナンバーをあさってようやくサンプルを見つけた時にはアゴが外れそうな勢いで驚きました
macOS 10.10以降でCocoaの機能が利用できるようになり、こうした配列に入れたレコードからデータを抽出するのに他のアプリケーションの機能を借りてくる必要がなくなりました。
正確にいえば、すべての配列要素を順次読み出して、指定の属性ラベルの値を調べて抽出といった地道な処理は昔からやっていましたが、そういうやり方だと、より高度な記述をしにくいところです。
AppleScript名:リストからフィールド内容を指定して抽出 |
— Created 2017-05-22 by Takaaki Naganoya — 2017 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" set aList to {{partOfSpeechLevel1:"名詞", baseForm:"北朝鮮", pronunciation:"キタチョーセン", position:0, partOfSpeechLevel3:"地域", reading:"キタチョウセン", surface:"北朝鮮", known:true, allFeatures:"名詞,固有名詞,地域,国,*,*,北朝鮮,キタチョウセン,キタチョーセン", conjugationType:"*", partOfSpeechLevel2:"固有名詞", conjugationForm:"*", allFeaturesArray:{"名詞", "固有名詞", "地域", "国", "*", "*", "北朝鮮", "キタチョウセン", "キタチョーセン"}, partOfSpeechLevel4:"国"}, {partOfSpeechLevel1:"記号", baseForm:"*", pronunciation:"*", position:3, partOfSpeechLevel3:"*", reading:"*", surface:":", known:false, allFeatures:"記号,一般,*,*,*,*,*,*,*", conjugationType:"*", partOfSpeechLevel2:"一般", conjugationForm:"*", allFeaturesArray:{"記号", "一般", "*", "*", "*", "*", "*", "*", "*"}, partOfSpeechLevel4:"*"}, {partOfSpeechLevel1:"接頭詞", baseForm:"正", pronunciation:"セイ", position:4, partOfSpeechLevel3:"*", reading:"セイ", surface:"正", known:true, allFeatures:"接頭詞,名詞接続,*,*,*,*,正,セイ,セイ", conjugationType:"*", partOfSpeechLevel2:"名詞接続", conjugationForm:"*", allFeaturesArray:{"接頭詞", "名詞接続", "*", "*", "*", "*", "正", "セイ", "セイ"}, partOfSpeechLevel4:"*"}, {partOfSpeechLevel1:"名詞", baseForm:"恩", pronunciation:"オン", position:5, partOfSpeechLevel3:"*", reading:"オン", surface:"恩", known:true, allFeatures:"名詞,一般,*,*,*,*,恩,オン,オン", conjugationType:"*", partOfSpeechLevel2:"一般", conjugationForm:"*", allFeaturesArray:{"名詞", "一般", "*", "*", "*", "*", "恩", "オン", "オン"}, partOfSpeechLevel4:"*"}, {partOfSpeechLevel1:"名詞", baseForm:"氏", pronunciation:"シ", position:6, partOfSpeechLevel3:"人名", reading:"シ", surface:"氏", known:true, allFeatures:"名詞,接尾,人名,*,*,*,氏,シ,シ", conjugationType:"*", partOfSpeechLevel2:"接尾", conjugationForm:"*", allFeaturesArray:{"名詞", "接尾", "人名", "*", "*", "*", "氏", "シ", "シ"}, partOfSpeechLevel4:"*"}, {partOfSpeechLevel1:"記号", baseForm:"「", pronunciation:"「", position:7, partOfSpeechLevel3:"*", reading:"「", surface:"「", known:true, allFeatures:"記号,括弧開,*,*,*,*,「,「,「", conjugationType:"*", partOfSpeechLevel2:"括弧開", conjugationForm:"*", allFeaturesArray:{"記号", "括弧開", "*", "*", "*", "*", "「", "「", "「"}, partOfSpeechLevel4:"*"}, {partOfSpeechLevel1:"名詞", baseForm:"北極星", pronunciation:"ホッキョクセイ", position:8, partOfSpeechLevel3:"一般", reading:"ホッキョクセイ", surface:"北極星", known:true, allFeatures:"名詞,固有名詞,一般,*,*,*,北極星,ホッキョクセイ,ホッキョクセイ", conjugationType:"*", partOfSpeechLevel2:"固有名詞", conjugationForm:"*", allFeaturesArray:{"名詞", "固有名詞", "一般", "*", "*", "*", "北極星", "ホッキョクセイ", "ホッキョクセイ"}, partOfSpeechLevel4:"*"}, {partOfSpeechLevel1:"名詞", baseForm:"2", pronunciation:"ニ", position:11, partOfSpeechLevel3:"*", reading:"ニ", surface:"2", known:true, allFeatures:"名詞,数,*,*,*,*,2,ニ,ニ", conjugationType:"*", partOfSpeechLevel2:"数", conjugationForm:"*", allFeaturesArray:{"名詞", "数", "*", "*", "*", "*", "2", "ニ", "ニ"}, partOfSpeechLevel4:"*"}, {partOfSpeechLevel1:"記号", baseForm:"」", pronunciation:"」", position:12, partOfSpeechLevel3:"*", reading:"」", surface:"」", known:true, allFeatures:"記号,括弧閉,*,*,*,*,」,」,」", conjugationType:"*", partOfSpeechLevel2:"括弧閉", conjugationForm:"*", allFeaturesArray:{"記号", "括弧閉", "*", "*", "*", "*", "」", "」", "」"}, partOfSpeechLevel4:"*"}, {partOfSpeechLevel1:"名詞", baseForm:"量産", pronunciation:"リョーサン", position:13, partOfSpeechLevel3:"*", reading:"リョウサン", surface:"量産", known:true, allFeatures:"名詞,サ変接続,*,*,*,*,量産,リョウサン,リョーサン", conjugationType:"*", partOfSpeechLevel2:"サ変接続", conjugationForm:"*", allFeaturesArray:{"名詞", "サ変接続", "*", "*", "*", "*", "量産", "リョウサン", "リョーサン"}, partOfSpeechLevel4:"*"}, {partOfSpeechLevel1:"名詞", baseForm:"指示", pronunciation:"シジ", position:15, partOfSpeechLevel3:"*", reading:"シジ", surface:"指示", known:true, allFeatures:"名詞,サ変接続,*,*,*,*,指示,シジ,シジ", conjugationType:"*", partOfSpeechLevel2:"サ変接続", conjugationForm:"*", allFeaturesArray:{"名詞", "サ変接続", "*", "*", "*", "*", "指示", "シジ", "シジ"}, partOfSpeechLevel4:"*"}, {partOfSpeechLevel1:"記号", baseForm:" ", pronunciation:" ", position:17, partOfSpeechLevel3:"*", reading:" ", surface:" ", known:true, allFeatures:"記号,空白,*,*,*,*, , , ", conjugationType:"*", partOfSpeechLevel2:"空白", conjugationForm:"*", allFeaturesArray:{"記号", "空白", "*", "*", "*", "*", " ", " ", " "}, partOfSpeechLevel4:"*"}, {partOfSpeechLevel1:"名詞", baseForm:"ミサイル", pronunciation:"ミサイル", position:18, partOfSpeechLevel3:"*", reading:"ミサイル", surface:"ミサイル", known:true, allFeatures:"名詞,一般,*,*,*,*,ミサイル,ミサイル,ミサイル", conjugationType:"*", partOfSpeechLevel2:"一般", conjugationForm:"*", allFeaturesArray:{"名詞", "一般", "*", "*", "*", "*", "ミサイル", "ミサイル", "ミサイル"}, partOfSpeechLevel4:"*"}, {partOfSpeechLevel1:"名詞", baseForm:"成功", pronunciation:"セイコー", position:22, partOfSpeechLevel3:"*", reading:"セイコウ", surface:"成功", known:true, allFeatures:"名詞,サ変接続,*,*,*,*,成功,セイコウ,セイコー", conjugationType:"*", partOfSpeechLevel2:"サ変接続", conjugationForm:"*", allFeaturesArray:{"名詞", "サ変接続", "*", "*", "*", "*", "成功", "セイコウ", "セイコー"}, partOfSpeechLevel4:"*"}, {partOfSpeechLevel1:"名詞", baseForm:"発表", pronunciation:"ハッピョー", position:24, partOfSpeechLevel3:"*", reading:"ハッピョウ", surface:"発表", known:true, allFeatures:"名詞,サ変接続,*,*,*,*,発表,ハッピョウ,ハッピョー", conjugationType:"*", partOfSpeechLevel2:"サ変接続", conjugationForm:"*", allFeaturesArray:{"名詞", "サ変接続", "*", "*", "*", "*", "発表", "ハッピョウ", "ハッピョー"}, partOfSpeechLevel4:"*"}} set anArray to current application’s NSMutableArray’s arrayWithArray:aList set aRes to (my filterRecListByLabel1(anArray, "allFeaturesArray contains[cd] ’固有名詞’"))’s baseForm –リストに入れたレコードを、指定の属性ラベルの値で抽出 on filterRecListByLabel1(aRecList as list, aPredicate as string) set aArray to current application’s NSArray’s arrayWithArray:aRecList set aPredicate to current application’s NSPredicate’s predicateWithFormat:aPredicate set filteredArray to aArray’s filteredArrayUsingPredicate:aPredicate return filteredArray end filterRecListByLabel1 |
配列の指定要素を検索する(テキスト)
配列(リスト)のうち、指定要素が何番目に登場するかを検索するAppleScriptです。
もともと、AppleScriptの配列に該当するリスト(list)は、非常に機能が素朴で、要素数を数える(length、count every item of)ほかはループで順次要素を取り出すとか、指定データが配列中に入っているかのチェックを行うとか(is in)、1番目の要素を取り出して元の配列から削除するといった程度の機能しかありません。「検索」については、データベース(FileMaker Proなど)に処理を依頼してね、というのが当初の立ち位置でした。
ただ、それだとたいした処理が書けないので、自力で配列の全要素をループして照合する、といった力技が全世界的に使われてきました。高速化を考慮しているとか、高度な技術を使っているとか、外部のOSAX(プラグイン形式の命令語拡張書類。macOS 10.14で廃止に)を利用するといっても「高級な力技」の域を出るものではありませんでした。
set aList to {9, 4, 2, 6, 4, 7}
set aTarg to 7
set aCount to 1
repeat with i in aList
set j to contents of i
if j = aTarg then
exit repeat
end if
set aCount to aCount + 1
end repeat
return aCount
★Click Here to Open This Script
macOS 10.6でXcode上記述するAppleScriptでCocoaの機能が利用できるようになり、macOS 10.10で通常のAppleScript上でもCocoaの機能が呼び出せるようになると、AppleScriptからCocoaの機能を利用することが検討されはじめました。
Cocoaの配列であるNSArray、NSMutableArrayは、多次元配列の作成や操作に難を抱えています(正直なところ、2次元配列の操作は補助プログラムを使わないとやりたくないレベル)。多次元配列の作成や操作ならCocoaの機能を使わずにAppleScriptだけで行なったほうが数億倍簡単です。
# その後、多次元配列専用のクラス「MLMultiArray」がCoreML.frameworkに用意されることになりました。AppleScriptからは直接アクセスできないんで、用はないんですが、、、
ただ、これらのCocoaの配列オブジェクトには検索や抽出などの機能があるため、複数キーによる検索程度なら少ない行数で記述することが可能です。さらに、いくつかの前提条件を満たせば、速度的なメリットもあります。
(1)AppleScriptの配列をCocoaの配列に変換するのに若干時間がかかる
まったく世界観が異なる世界の配列を変換するのに、若干時間がかかります。そのため、AppleScriptからCocoaの配列を使う目的が「スピードアップ」だとしたら、それに見合った「巨大なデータ」が処理対象であることが前提条件です。目安としては、AppleScriptの配列のアクセスが遅くなってくる(高速化処理を行えば、そのかぎりではありませんが)4,000項目以上、もう少しいえば10,000項目の配列の処理ぐらいでないと速度向上のメリットを感じにくいところです。
また、Cocoaの配列が持っている条件抽出や正規表現による抽出を使うぐらいでないと、「ただ漫然とループする」ぐらいでは使う価値がありません。
(2)Cocoaの配列にAppleScriptの世界のアプリケーションのオブジェクトを入れられない
Cocoaの配列には、AppleScript上で普通に扱っている「Photoshopの最前面のドキュメント」とか「iTunesで選択中の音楽トラック」といったオブジェクトを直接入れることはできません。これらのオブジェクトのIDを取り出して、「単なる数値」として扱うのであれば別ですが、これらのアプリケーションのオブジェクトをCocoaの配列に入れることはできません。
(3)AppleScriptの配列(リスト)とCocoaの配列(NSArray/NSMutableArray)はアイテムの開始値が違う
普通、配列といえば0番目の要素から始まりますが、AppleScriptでは1番目から始まります。そのため、Cocoaの配列の機能を利用するときには、これらの仕様の違いを念頭におく必要があります。
ここで紹介するのは、Cocoaの配列を作ってCocoaの配列の機能を利用して指定要素の登場位置を求めるものです。さらに、Cocoaのバグ(OSのバグ)に対処するために若干の処理を追加してあります。macOS 10.12〜10.13の間、定数「NSNotFound」の定義が間違ったまま出荷されていました。その値がAppleScriptで扱える範囲を超える巨大な定義値だったために、そのバグの影響を受けました。
過去の情報を調べてみたところ、AppleがNSNotFoundの定義値を間違えてOSを出荷するというのはこれが初めてのことではありません(2度目か3度目)。そんな基礎的かつ重要な値の定義を間違えるなんて●●としか思えないのですが、そういうことのようです。
AppleがNSNotFoundの定義値を今後も間違える可能性があるため、本来シンプルで済むはずの記述でもこの程度の対処が必要となります。
AppleScript名:AppleScript名:配列の指定要素を検索する(テキスト) |
— Created 2015-09-02 by Takaaki Naganoya — 2015 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" set aList to {"AAAAAAAAAAAAAAAAAAA", "BBBBBBBBBBBBBBBBBBBBB", "CCCCCCCCCCCCCCCCCCCCCCCC"} set anArray to current application’s NSArray’s arrayWithArray:aList –> (NSArray) {"AAAAAAAAAAAAAAAAAAA", "BBBBBBBBBBBBBBBBBBBBB", "CCCCCCCCCCCCCCCCCCCCCCCC"} –指定要素を検索する set aInd to anArray’s indexOfObject:"CCCCCCCCCCCCCCCCCCCCCCCC" if (aInd = current application’s NSNotFound) or (aInd > 9.999999999E+9) then return false else return aInd –> 2 end if |
1D List内の文字検索(完全一致)
AppleScript名:1D List内の文字検索(完全一致) |
— Created 2015-09-02 by Takaaki Naganoya — 2015 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" property |NSURL| : a reference to current application’s |NSURL| property NSArray : a reference to current application’s NSArray property NSPredicate : a reference to current application’s NSPredicate property NSFileManager : a reference to current application’s NSFileManager property NSMutableArray : a reference to current application’s NSMutableArray property NSSortDescriptor : a reference to current application’s NSSortDescriptor property NSURLIsDirectoryKey : a reference to current application’s NSURLIsDirectoryKey property NSDirectoryEnumerationSkipsHiddenFiles : a reference to current application’s NSDirectoryEnumerationSkipsHiddenFiles property NSDirectoryEnumerationSkipsPackageDescendants : a reference to current application’s NSDirectoryEnumerationSkipsPackageDescendants property NSDirectoryEnumerationSkipsSubdirectoryDescendants : a reference to current application’s NSDirectoryEnumerationSkipsSubdirectoryDescendants set aFol to choose folder set aList to my getFilesByIncludedStringInName:("txt") fromDirectory:(POSIX path of aFol) exceptPackages:(true) –return aList –set aList to {"AAAAAAAAAAAAAAAAAAA", "BBBBBBBBBBBBBBBBBBBBB", "CCCCCCCCCCCCCCCCCCCCCCCC"} set anArray to current application’s NSArray’s arrayWithArray:aList –> (NSArray) {1, 2, 3} –指定要素を検索する set aInd to anArray’s indexOfObject:"N7663CT-673.txt" if (aInd = current application’s NSNotFound) or (aInd > 9.999999999E+9) then return false else return aInd –> 2 end if –指定フォルダ内の指定文字列を含むファイル名のファイルをPOSIX pathのlistで抽出する on getFilesByIncludedStringInName:(fileNameStr as string) fromDirectory:(sourceFolder) exceptPackages:(packageF as boolean) set fileManager to NSFileManager’s defaultManager() set aURL to |NSURL|’s fileURLWithPath:sourceFolder set theOptions to ((NSDirectoryEnumerationSkipsPackageDescendants) as integer) + ((NSDirectoryEnumerationSkipsHiddenFiles) as integer) + ((NSDirectoryEnumerationSkipsSubdirectoryDescendants) as integer) set directoryContents to fileManager’s contentsOfDirectoryAtURL:aURL includingPropertiesForKeys:{} options:theOptions |error|:(missing value) set findPredicates to NSPredicate’s predicateWithFormat_("lastPathComponent CONTAINS %@", fileNameStr) set foundItemList to directoryContents’s filteredArrayUsingPredicate:findPredicates –Remove Folders From found URL Array set anArray to NSMutableArray’s alloc()’s init() repeat with i in foundItemList set j to contents of i set {theResult, isDirectory} to (j’s getResourceValue:(reference) forKey:(NSURLIsDirectoryKey) |error|:(missing value)) –Collect files if (isDirectory as boolean = false) then (anArray’s addObject:j) else if (packageF = false) then –Allow Package files? set {theResult, isPackage} to (j’s getResourceValue:(reference) forKey:(current application’s NSURLIsPackageKey) |error|:(missing value)) if (isPackage as boolean) = true then (anArray’s addObject:j) end if end if end repeat return (anArray’s valueForKey:"lastPathComponent") as list end getFilesByIncludedStringInName:fromDirectory:exceptPackages: |
1D List内の文字、数値検索
AppleScript名:1D List内の文字、数値検索 |
use AppleScript version "2.4" use scripting additions use framework "Foundation" set aList to {5, 2, 3, 4, 1} set aRes to findItemNumFrom1DArray(aList, 5, false) of me –> 1 set aRes to findItemNumFrom1DArray(aList, 5, true) of me –> 5 set aList to {"1", "2", "3", "4", "5"} set aRes to findItemNumFrom1DArray(aList, "3", false) of me –> 3 on findItemNumFrom1DArray(aList as list, targItem as list of string or string, sortSW as boolean) set anArray to current application’s NSArray’s arrayWithArray:aList if sortSW = true then set anArray to anArray’s sortedArrayUsingSelector:"compare:" end if set aInd to anArray’s indexOfObject:targItem if (aInd = current application’s NSNotFound) or (aInd > 9.999999999E+9) then return false else return (aInd + 1) as integer end if end findItemNumFrom1DArray |
単語ベースの文字列間のdiffをとる(NSMutableSet)
AppleScript名:単語ベースの文字列間のdiffをとる(NSMutableSet) |
— Created 2016-02-21 by Takaaki Naganoya — 2016 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" set str1 to current application’s NSString’s stringWithString:"My cat sometimes likes to eat fish." set str2 to current application’s NSString’s stringWithString:"My cat always likes to drink fresh water, and eat fish." set set1 to current application’s NSMutableSet’s setWithArray:(str1’s componentsSeparatedByString:" ") set set2 to current application’s NSMutableSet’s setWithArray:(str2’s componentsSeparatedByString:" ") set2’s minusSet:set1 set anArray to (set2’s allObjects()) as list –> {"always", "water,", "and", "drink", "fresh"}–str1になくてstr2にあるもの set set3 to current application’s NSMutableSet’s setWithArray:(str1’s componentsSeparatedByString:" ") set set4 to current application’s NSMutableSet’s setWithArray:(str2’s componentsSeparatedByString:" ") set4’s unionSet:set3 set anArray to (set4’s allObjects()) as list –> {"to", "water,", "My", "cat", "likes", "fish.", "drink", "eat", "and", "fresh", "always", "sometimes"}–合成してユニーク化 set set5 to current application’s NSMutableSet’s setWithArray:(str1’s componentsSeparatedByString:" ") set set6 to current application’s NSMutableSet’s setWithArray:(str2’s componentsSeparatedByString:" ") set6’s intersectSet:set5 set anArray to (set6’s allObjects()) as list –> {"eat", "My", "cat", "likes", "to", "fish."}–共通項 set set7 to current application’s NSMutableSet’s setWithArray:(str1’s componentsSeparatedByString:" ") set set8 to current application’s NSMutableSet’s setWithArray:(str2’s componentsSeparatedByString:" ") set8’s setSet:set7 set anArray to (set8’s allObjects()) as list –> {"eat", "sometimes", "My", "cat", "likes", "to", "fish."}–置き換え。NSMutableSet配列の要素を全て削除し、指定したNSSet配列のオブジェクトを追加する |
1D List中の最頻出項目を抽出する
AppleScript名:1D List中の最頻出項目を抽出する |
— Created 2016-11-15 by Takaaki Naganoya — 2016 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" set aList to {"positive", "negative", "positive", "positive", "positive"} set bList to countItemsByItsAppearance(aList) of me –> {{theName:"positive", numberOfTimes:4}, {theName:"negative", numberOfTimes:1}} set aRes to theName of contents of first item of bList –> "positive" on countItemsByItsAppearance(aList) set aSet to current application’s NSCountedSet’s alloc()’s initWithArray:aList set bArray to current application’s NSMutableArray’s array() set theEnumerator to aSet’s objectEnumerator() repeat set aValue to theEnumerator’s nextObject() if aValue is missing value then exit repeat bArray’s addObject:(current application’s NSDictionary’s dictionaryWithObjects:{aValue, (aSet’s countForObject:aValue)} forKeys:{"theName", "numberOfTimes"}) end repeat –出現回数(numberOfTimes)で降順ソート set theDesc to current application’s NSSortDescriptor’s sortDescriptorWithKey:"numberOfTimes" ascending:false bArray’s sortUsingDescriptors:{theDesc} return bArray as list end countItemsByItsAppearance |
配列に指定要素が含まれているかチェック
AppleScript名:配列に指定要素が含まれているかチェック |
— Created 2015-09-02 by Takaaki Naganoya — 2015 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" set anArray to current application’s NSArray’s arrayWithObjects_(1, 2, 3) –> (NSArray) {1, 2, 3} –指定要素が含まれているか set bRes to (anArray’s containsObject:1) as boolean –> true set cRes to (anArray’s containsObject:100) as boolean –> false |
1D List中の存在確認(ASOC)
AppleScript名:1D List中の存在確認(ASOC) |
— Created 2017-10-03 17:56:08 +0900 by Takaaki Naganoya — 2017 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" set kinsokuCharList to {"︒", "︑", "﹁", "﹂", "﹃", "﹄", "︻", "︼", "﹇", "﹈", "︷", "︸", "︵", "︶", "︱", "⌇", "ァ", "ィ", "ゥ", "ェ", "ォ", "ョ", "ぁ", "ぃ", "ぅ", "ぇ", "ぉ", "ょ"} set aRes to offsetInList("ぁ", kinsokuCharList) of me –> 22 set aRes to offsetInList("あ", kinsokuCharList) of me on offsetInList(aChar, aList) set anArray to current application’s NSArray’s arrayWithArray:aList set aInd to (anArray’s indexOfObject:aChar) if aInd = current application’s NSNotFound or (aInd as number) > 9.99999999E+8 then return false else return aInd as integer end if end offsetInList |
1D List中の存在確認(n vs n)
AppleScript名:1D List中の存在確認(n vs n) |
— Created 2017-10-29 by Takaaki Naganoya — 2017 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" set list1 to {5, 1, 2, 3, 1, 6, 2, 7, 8, 2, 6, 5, 4} set list2 to {8, 9, 10} set list3 to {6, 7, 8} set result1 to my doesList:list1 containList:list2 –> false set result2 to my doesList:list1 containList:list3 –> true set result1 to doesListContain for list1 by list2 –> false set result1 to doesListContain for list1 by list3 –> true set result1 to doesListContainAB(list1, list2) of me –> false set result2 to doesListContainAB(list1, list3) of me –> true –Objective-Cライクなパラメータ記述 on doesList:list1 containList:list2 set set1 to current application’s NSSet’s setWithArray:list1 set set2 to current application’s NSSet’s setWithArray:list2 return ((set2’s isSubsetOfSet:set1) as integer = 1) end doesList:containList: –無意味区による装飾 on doesListContain for list1 by list2 set result1 to my doesList:list1 containList:list2 return result1 end doesListContain –Pure AS風のパラメータ記述 on doesListContainAB(list1, list2) set result1 to my doesList:list1 containList:list2 return result1 end doesListContainAB |