Archive for the 'NSSet' Category

2017/08/19 PDFの指定ページを削除 v4(複数ページ一括指定)

指定PDF書類のうちの指定ページをまとめて削除するAppleScriptです。

ページ指定にプラスの数値を指定すると絶対ページ数、マイナスの数値を指定するとページ末尾からの相対ページ数として解釈されます。ページ削除前に削除対象のページ数をすべて絶対ページに変換しつつ、重複分を削除し、削除対象ページを降順ソートします。

常識的な範囲内では、PDFからの指定ページ削除は行えるはずです。

ただ、この程度の実装だとすべてのPDFを対象にできないので困ります。Mac App Storeで販売中のアプリ「Double PDF」ではこのあたりの問題を解決したPDF処理ルーチンを仕込んであります。

AppleScript名:PDFの指定ページを削除 v4(複数ページ一括指定)
– Modified 2017-08-19 by Takaaki Naganoya
–Original By Shane Stanley
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “Quartz”
–http://piyocast.com/as/archives/4784

property NSSortDescriptor : a reference to current application’s NSSortDescriptor
property NSArray : a reference to current application’s NSArray
property NSSet : a reference to current application’s NSSet
property |NSURL| : a reference to current application’s |NSURL|
property PDFDocument : a reference to current application’s PDFDocument

set inFile to (choose file of type {“pdf”} with prompt “Choose your PDF files:”)
set targPageList to {1, 3, 5, 7, -1, -2}

set pRes to removeSpecificPagesFromPDF(inFile, targPageList) of me

–指定PDF書類の複数ページの一括削除
on removeSpecificPagesFromPDF(inFileAlias, targPageNumList as list)
  set inNSURL to |NSURL|’s fileURLWithPath:(POSIX path of inFileAlias)
  
set theDoc to PDFDocument’s alloc()’s initWithURL:inNSURL
  
  
–削除対象ページリストをユニーク化して降順ソート(後方から削除)
  
set pRes to theDoc’s pageCount()
  
set t3List to relativeToAbsNumList(targPageNumList, pRes) of me
  
  
repeat with i in t3List
    copy i to targPageNum
    (
theDoc’s removePageAtIndex:(targPageNum - 1))
  end repeat
  
  
–Overwrite Exsiting PDF
  
set aRes to (theDoc’s writeToURL:inNSURL) as boolean
  
  
return aRes
end removeSpecificPagesFromPDF

–絶対ページと相対ページが混在した削除対象ページリストを絶対ページに変換して重複削除して降順ソート
on relativeToAbsNumList(aList, aMax)
  set newList to {}
  
  
repeat with i in aList
    set j to contents of i
    
if i < 0 then
      set j to aMax + j
    end if
    
    
if (j aMax) and (j is not equal to 0) then
      set the end of newList to j
    end if
  end repeat
  
  
set t1List to my uniquify1DList(newList, true)
  
set t2List to my sort1DNumList:t1List ascOrder:false
  
  
return t2List
end relativeToAbsNumList

on absNum(q)
  if q is less than 0 then set q to -q
  
return q
end absNum

–1D/2D Listをユニーク化
on uniquify1DList(theList as list, aBool as boolean)
  set aArray to NSArray’s arrayWithArray:theList
  
set bArray to aArray’s valueForKeyPath:“@distinctUnionOfObjects.self”
  
return bArray as list
end uniquify1DList

–Sort 1-Dimension List(String Number List)
on sort1DNumList:theList ascOrder:aBool
  tell NSSet to set theSet to setWithArray_(theList)
  
tell NSSortDescriptor to set theDescriptor to sortDescriptorWithKey_ascending_(“floatValue”, aBool)
  
set sortedList to theSet’s sortedArrayUsingDescriptors:{theDescriptor}
  
return (sortedList) as list
end sort1DNumList:ascOrder:

★Click Here to Open This Script 

2017/03/01 NSSet/NSMutableSetの演算 2

NSSet/NSMutableSetの演算について、Shane Stanleyから「こっちのほうが短く書けるぞ」というツッコミが(Thanks!)。

set1.png

AppleScript名:補集合(set difference)v2
– Created 2017-02-24 by Takaaki Naganoya
– Created 2017-03-01 by Shane Stanley
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
–http://piyocast.com/as/archives/4491

set aSet to current application’s NSMutableSet’s setWithArray:{1, 2, 3, 4}
set bSet to current application’s NSMutableSet’s setWithArray:{3, 5, 6, 7}

aSet’s minusSet:bSet –補集合
aSet’s allObjects() as list
–>  {2, 1, 4}

★Click Here to Open This Script 

set2.png

AppleScript名:積集合(product)v2
– Created 2017-02-24 by Takaaki Naganoya
– Created 2017-03-01 by Shane Stanley
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
–http://piyocast.com/as/archives/4491

set aSet to current application’s NSMutableSet’s setWithArray:{1, 2, 3, 4}
set bSet to current application’s NSMutableSet’s setWithArray:{3, 5, 6, 7}

aSet’s intersectSet:bSet –積集合
aSet’s allObjects() as list
–>  {3}

★Click Here to Open This Script 

set3.png

AppleScript名:和集合(union)v2
– Created 2017-02-24 by Takaaki Naganoya
– Created 2017-03-01 by Shane Stanley
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
–http://piyocast.com/as/archives/4491

set aSet to current application’s NSMutableSet’s setWithArray:{1, 2, 3, 4}
set bSet to current application’s NSMutableSet’s setWithArray:{3, 5, 6, 7}

aSet’s unionSet:bSet –和集合
aSet’s allObjects() as list
–>  {5, 1, 6, 2, 7, 3, 4}

★Click Here to Open This Script 

2017/02/23 リストから重複要素のみを返す v2

Shane Stanleyによる「リストから重複する要素のみを抽出して返すAppleScript」の改良版です。シンプルで美しい処理になっています。

この手の処理でNSSetやNSCountedSetを使うのは「そういうものだろー」とすぐに思いつきますが、「minusSet:」というのはドキュメント中から見つけ切れませんでした。これは深い(^ー^;;。

また、ループ処理や条件判断の処理が入っていないため、自分の書いたバージョンよりも2.3倍ぐらい高速でした(100回実行時の平均)。

AppleScript名:リストから重複要素のみを返す v2
– Created 2017-02-23 by Shane Stanley
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4469

set aList to {“4efa7f9f587f3d1dbc4a1f6ebff92ef5″, “59cd07ea69acc2c9004dc815803cf184″, “5841f4bcc13e85c3b8ba1eafcacd43be”, “dfb393cd3c0eb3f228236367f171cd01″, “59cd07ea69acc2c9004dc815803cf184″, “59cd07ea69acc2c9004dc815803cf184″}
set dList to returnDuplicatesOnly(aList) of me
–> {”59cd07ea69acc2c9004dc815803cf184″}

on returnDuplicatesOnly(aList)
  set countedSet to current application’s NSCountedSet’s alloc()’s initWithArray:aList
  
set simpleSet to current application’s NSSet’s setWithArray:aList
  
countedSet’s minusSet:simpleSet
  
return countedSet’s allObjects() as list
end returnDuplicatesOnly

★Click Here to Open This Script 

2016/12/14 レコードのうち、最大の値を持つKeyを返す

レコードのうち、最大の値を持つキーを返すAppleScriptです。

AppleScriptからMicrosoftの表情認識APIを呼び出せるようになったはいいものの、得られたデータからどの表情の可能性が高いかを判定する必要があり、そのために書いてみたものです。

Cocoaの機能を用いて、レコードのキーを取り出したり、さまざまな処理を行っています。こうした処理が手軽にできるようになったのは、実にいいことです。

さらに、画像から顔認識を行い、表情を読み取ってデータ化できるというのは、実に素晴らしいと思うものです。

ただ、いろいろ実験を行ってみたところ・・・恐れとか悲しみとか軽蔑といった微妙な感情については検出しづらいことがわかってきました。最大の値のものをピックアップするという方法ではなく、微妙な感情については別途評価を行う必要がありそうです。

mona_lisa_by_leonardo_da_vinci_from_c2rmf_retouched-1.jpg
–> “neutral”

donaldtrump61815_resized.png
–> “anger”

AppleScript名:レコードのうち、最大の値を持つKeyを返す
– Created 2016-12-14 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4359

set aDict to current application’s NSDictionary’s dictionaryWithDictionary:{sadness:0.01133416, anger:1.03975857E-4, happiness:2.90919736E-4, fear:2.28432211E-4, neutral:0.9830475, contempt:2.4698046E-4, disgust:1.02946949E-4, surprise:0.00464509334}
set aMacKey to retMaxValueKey(aDict) of me
–>  ”neutral”

on retMaxValueKey(aDict)
  set aValList to aDict’s allValues()
  
set maxVal to (sort1DNumList(aValList, false) of me)’s firstObject()
  
set keyList to (aDict’s allKeys()) as list
  
  
repeat with i in keyList
    set j to contents of i
    
set aTmp to (aDict’s valueForKey:j)
    
set aRes to compareNumerically(maxVal, aTmp) of me
    
if aRes = true then return j
  end repeat
  
  
return false
end retMaxValueKey

–Numerical Strings Compare
on compareNumerically(aText as text, bText as text)
  set aStr to current application’s NSString’s stringWithString:aText
  
return (aStr’s compare:bText options:(current application’s NSNumericSearch)) = current application’s NSOrderedSame
end compareNumerically

–1D List(数値)をsort / ascOrderがtrueだと昇順ソート、falseだと降順ソート
on sort1DNumList(theList, aBool)
  set theSet to current application’s NSSet’s setWithArray:theList
  
set theDescriptor to current application’s NSSortDescriptor’s sortDescriptorWithKey:(missing value) ascending:aBool
  
set sortedList to theSet’s sortedArrayUsingDescriptors:{theDescriptor}
  
return (sortedList)
end sort1DNumList

★Click Here to Open This Script 

2015/10/22 辞書.appの指定名称の辞書でキーワード検索

オープンソースのプログラムDictionaryKit(By Mattt Thompson)をフレームワークに入れた「dictKit」を介して、OS X内蔵の辞書でキーワード検索を行うAppleScriptです。

DictionaryKitの内部機能を直接AppleScriptから呼ぶことはできませんが、DictionaryKitのプログラムを突っ込んだFramework「dictKit.framework」を作成し、これをインストールしてAppleScriptから呼べるようにしました。

注意点:DictionaryKitの説明にもあるのですが、OS XのPrivate APIを呼んでいるため、本プログラム(dictKit)を用いて作ったアプリケーションをMac App Store向けに申請することはできません。

でも、超〜便利なんで(^ー^;;; 日常的なScriptで使わない手はありません。

例によって、dictKitのバイナリをOS X 10.10以降用にビルドしておきましたので、興味のある方は~/Library/Frameworksフォルダに入れておためしください。

–> Download Framework Binary

AppleScript名:ASOCで辞書.appで検索可能な辞書名称一覧を取得する
– Created 2015-10-22 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “dictKit” –mattt/DictionaryKit
–https://github.com/mattt/DictionaryKit

set dSet to current application’s TTTDictionary’s availableDictionaries()
set dList to dSet’s allObjects()
set dNameList to {}
repeat with i in dList
  set the end of dNameList to (i’s |name|()) as text
end repeat
dNameList
–>  {”뉴에이스 영한사전 / 뉴에이스 한영사전“, “Apple 用語辞典”, “Multidictionnaire de la langue française”, “राजपाल हिन्दी शब्दकोश“, “Dizionario italiano da un affiliato di Oxford University Press”, “Oxford-Hachette French Dictionary”, “NE Ordbok”, “牛津英汉汉典”, “Oxford Thesaurus of English”, “スーパー大辞林”, “Oxford Dictionary of English”, “Oxford American Writer’s Thesaurus”, “Norsk Ordbok”, “Gran Diccionario Oxford - Español-Inglés Inglés-Español”, “Wikipedia”, “Duden-Wissensnetz deutsche Sprache”, “Толковый словарь русского языка”, “뉴에이스 국어사전“, “Prisma woordenboek Nederlands”, “New Oxford American Dictionary”, “Dicionário de Português licenciado para Oxford University Press”, “Oxford German Dictionary”, “Diccionario General de la Lengua Española Vox”, “ウィズダム英和辞典 / ウィズダム和英辞典”, “Arkadaş Türkçe Sözlük”, “พจนานุกรมไทย ฉบับทันสมัยและสมบูรณ์“, “汉语规典”}

★Click Here to Open This Script 

AppleScript名:ASOCで辞書検索じっけん
– Created 2015-10-22 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “dictKit” –mattt/DictionaryKit
–https://github.com/mattt/DictionaryKit

set aDictionary to current application’s TTTDictionary’s dictionaryNamed:“Apple 用語辞典”
set dRes to aDictionary’s |name|()
set dRes to dRes as text
–>  ”Apple 用語辞典”

set aTerm to “AppleScript”
set hitEntryList to (aDictionary’s entriesForSearchTerm:aTerm) as list
if hitEntryList = {missing value} then return “” –ヒットしなかった場合

repeat with i in hitEntryList
  set j to contents of i
  
  
set headW to (j’s headword)
  
set headW to headW as text
  
–>  ”AppleScript”
  
  
set aText to (j’s |text|)
  
set aText to aText as text
  
(*)
  –>  ”AppleScript
OS X に内蔵されたスクリプト言語です。AppleScript 言語のコマンドを使用すれば、“メール”、Safari、“カレンダー”など、さまざまなアプリケーションで繰り返しの作業や複雑な作業を自動化できます。
*)

  
end repeat

★Click Here to Open This Script 

2015/07/23 ASOCでレコードのリストをユニーク化

レコードのリスト(例:{{namae:”Piyomaru”,age:16}, {namae:”Piyoko”, age:13}})で、重複データ項目があった場合にそなえ、重複項目を削除する「ユニーク化」を行うAppleScriptObjCのScriptです。

BridgePlusを用いたバージョンと、ASObjCExtras.frameworkを用いたバージョンを掲載します。現在ではBridgePlusの使用が強く推奨されています。

AppleScript名:ASOCでレコードのリストをユニーク化(BridgePlus)
use AppleScript version “2.4″
use framework “Foundation”
use scripting additions
use script “BridgePlus”

load framework

set msRecList to {{msName:“格 陸戦型ジム 獲得済 COST: 120″, sortieTimes:12}, {msName:“狙 ジム・スナイパーカスタム 獲得済 COST: 200″, sortieTimes:6}, {msName:“狙 ジム・スナイパーカスタム 獲得済 COST: 200″, sortieTimes:6}}

set newMsList to uniquefyList(msRecList)
–>  {{sortieTimes:6, msName:”狙 ジム・スナイパーカスタム 獲得済 COST: 200″}, {sortieTimes:12, msName:”格 陸戦型ジム 獲得済 COST: 120″}}

–レコードのリストをユニーク化
on uniquefyList(aList)
  set msArray to Cocoaify aList
  
set aRes to current application’s NSSet’s setWithArray:(msArray’s allObjects())
  
set bRes to aRes’s allObjects()
  
set cRes to ASify from bRes as list
  
return cRes
end uniquefyList

★Click Here to Open This Script 

AppleScript名:ASOCでレコードのリストをユニーク化(ASObjCExtras.framework)
use AppleScript version “2.4″
use framework “Foundation”
use framework “ASObjCExtras”
use scripting additions

set msRecList to {{msName:“格 陸戦型ジム 獲得済 COST: 120″, sortieTimes:12}, {msName:“狙 ジム・スナイパーカスタム 獲得済 COST: 200″, sortieTimes:6}, {msName:“狙 ジム・スナイパーカスタム 獲得済 COST: 200″, sortieTimes:6}}

set newMsList to uniquefyList(msRecList)
–>  {{sortieTimes:6, msName:”狙 ジム・スナイパーカスタム 獲得済 COST: 200″}, {sortieTimes:12, msName:”格 陸戦型ジム 獲得済 COST: 120″}}

–レコードのリストをユニーク化
on uniquefyList(aList)
  set msArray to current application’s SMSFord’s Cocoaify:aList
  
set aRes to current application’s NSSet’s setWithArray:(msArray’s allObjects())
  
set bRes to aRes’s allObjects()
  
set cRes to bRes’s ASify() as list
  
return cRes
end uniquefyList

★Click Here to Open This Script 

2014/11/21 1D Listのユニーク化(asoc) 処理内容比較

1D Listのユニーク化の方法について、Shane Stanleyからいろいろと助言をもらいました。

Shaneは処理速度について高速化のために提案してくれたのですが、10万アイテムのListに対して10回計測で平均をとってみたら、「いずれも高速ではあるものの、それほど変わらない」という結果に(#1より#2,#3の方が微妙に高速)。

問題は、ユニーク化したあとの結果。ソートされているものもあれば、されていないものもある、という状況。

少々疑問点があったので、小数点以下の値やマイナスの値などいろいろ突っ込んで追試に次ぐ追試を行ってみたところ・・・数値リストのユニーク化については、結果はどれも「ソートずみの値」として使ってはいけないということに。

uniquify.png

AppleScript名:listのユニーク化(asoc)_method1
– Created 2014-11-19 by Takaaki Naganoya
– 2014 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”

set aList to {-1, 4, 4, 4, 4, 4, 1, 2, 3, 1, 2, 1.1, -1.1}

set aArray to current application’s NSArray’s arrayWithArray:aList
set bArray to aArray’s valueForKeyPath:“@distinctUnionOfObjects.self”

set bList to bArray’s ASify() as list
–> {3, -1, 1, 1.1, -1.1, 4, 2}

★Click Here to Open This Script 

AppleScript名:listのユニーク化(asoc)_method2
–By Shane Stanley
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”

set aList to {-1, 4, 4, 4, 4, 4, 1, 2, 3, 1, 2, 1.1, -1.1}

set theSet to current application’s NSOrderedSet’s orderedSetWithArray:aList
set bArray to theSet’s array() – get set’s items as array
set bList to bArray’s ASify() as list
–> {-1, 4, 1, 2, 3, 1.1, -1.1}

★Click Here to Open This Script 

AppleScript名:listのユニーク化(asoc)_method3
–By Shane Stanley
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”

set aList to {-1, 4, 4, 4, 4, 4, 1, 2, 3, 1, 2, 1.1, -1.1}

set theSet to current application’s NSSet’s setWithArray:aList
set bArray to theSet’s allObjects() – get set’s items as array
set bList to bArray’s ASify() as list
–>{3, -1, 1, 1.1, -1.1, 4, 2}

★Click Here to Open This Script 

2014/11/18 listの共通項を返す(asoc)

2つのListをくらべて、共通項を返すAppleScriptです。

Cocoaの流儀にしたがって、Cocoaの機能を使って実装してみました。

AppleScript名:listの共通項を返す
– Created 2014-11-18 by Takaaki Naganoya
– 2014 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”

set aList to {1, 2, 3, 4, 5}
set bList to {0, 1, 2, 4, 5, 6}

set aRes to getSameItemsInLists(aList, bList) of me
–> {2, 5, 1, 4}

on getSameItemsInLists(aList as list, bList as list)
  
  
–ASオブジェクトをCocoaオブジェクトに変換
  
set aArray to current application’s NSArray’s arrayWithArray:aList
  
set bArray to current application’s NSArray’s arrayWithArray:bList
  
  
– まとめる
  
set allSet to current application’s NSMutableSet’s setWithArray:aArray
  
allSet’s addObjectsFromArray:bArray
  
  
–重複する要素のみ抜き出す
  
set duplicateSet to current application’s NSMutableSet’s setWithArray:aArray
  
duplicateSet’s intersectSet:(current application’s NSSet’s setWithArray:bArray)
  
  
–重複部分だけを返す
  
set resArray to duplicateSet’s allObjects()
  
  
set resList to resArray’s ASify() as list
  
  
return resList
  
end getSameItemsInLists

★Click Here to Open This Script 

2014/11/18 list同士のdiffをとる(asoc)

2つのListのdiffをとるAppleScriptです。

検索していろいろ調べ、主にこちらのページの内容を参考にして、Cocoaの流儀にしたがって、Cocoaの機能を使って実装してみました。

以前にAppleScriptだけで実装したものもありますが、データ量が増えるとこちらの方が有利と思われます。

・・・などと書いていたら、Shane Stanleyが2つのAppleScriptの実行速度を計測するツール「Script Geek v.1.27」を公開していました

geek.png

この用途のために作られたとしか思えないツールなので、素直に使っておきましょう。指定回数実行して、平均実行時間を計測してくれるツールです。

実際に使ってみると、

(1)テストデータ作成部分を時間計測してほしくない
(2)計測結果をグラフ表示してほしい
(3)テスト中に画面の内容をアップデートしたほうがいい

といった率直な感想が(^ー^;;

それはいいとして、ASだけで実装したものとASOCで実装したものだとASOCの方が120倍速いという結果が出ました。ASだけで実装した方は、けっこう忙しいときに書いたらしく処理内容が入り組んでおり「どうしてこう書いたんだろう」という話が思い出せません、、、

また、繰り返し実行するとASOCの処理速度が(一桁ぐらい)上がるのに驚きました(初回実行時は0.27秒なのに、平均実行速度が0.03秒、、、)。

(4)各計測結果を数値またはグラフで表示

があると、どういった傾向があるのか分かってよいでしょう。

AppleScript名:listのdiffをとる
– Created 2014-11-18 by Takaaki Naganoya
– 2014 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”

set aList to {1, 2, 3, 4, 5}
set bList to {0, 1, 2, 4, 5, 6}

set aRes to diffLists(aList, bList) of me
–> {0, 6, 3}

on diffLists(aList as list, bList as list)
  –以下を参照
  
–http://qiita.com/ar_tama/items/b69d6ab5c505be89c414
  
  
–ASオブジェクトをCocoaオブジェクトに変換
  
set aArray to current application’s NSArray’s arrayWithArray:aList
  
set bArray to current application’s NSArray’s arrayWithArray:bList
  
  
– まとめる
  
set allSet to current application’s NSMutableSet’s setWithArray:aArray
  
allSet’s addObjectsFromArray:bArray
  
  
–重複する要素のみ抜き出す
  
set duplicateSet to current application’s NSMutableSet’s setWithArray:aArray
  
duplicateSet’s intersectSet:(current application’s NSSet’s setWithArray:bArray)
  
  
–重複部分を削除する
  
allSet’s minusSet:duplicateSet
  
set resArray to allSet’s allObjects()
  
  
set resList to resArray’s ASify() as list
  
  
return resList
  
end diffLists

★Click Here to Open This Script 

AppleScript名:listのdiffをとる(時間計測用)
– Created 2014-11-18 by Takaaki Naganoya
– 2014 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”

script spd
  property aList : {}
  
property bList : {}
end script

set aList of spd to {}
set bList of spd to {}

repeat 1000 times
  set the end of aList of spd to random number from 1 to 1000
  
set the end of bList of spd to random number from 1 to 1000
end repeat

set aRes to diffLists(aList of spd, bList of spd) of me

on diffLists(aList as list, bList as list)
  –以下を参照
  
–http://qiita.com/ar_tama/items/b69d6ab5c505be89c414
  
  
–ASオブジェクトをCocoaオブジェクトに変換
  
set aArray to current application’s NSArray’s arrayWithArray:aList
  
set bArray to current application’s NSArray’s arrayWithArray:bList
  
  
– まとめる
  
set allSet to current application’s NSMutableSet’s setWithArray:aArray
  
allSet’s addObjectsFromArray:bArray
  
  
–重複する要素のみ抜き出す
  
set duplicateSet to current application’s NSMutableSet’s setWithArray:aArray
  
duplicateSet’s intersectSet:(current application’s NSSet’s setWithArray:bArray)
  
  
–重複部分を削除する
  
allSet’s minusSet:duplicateSet
  
set resArray to allSet’s allObjects()
  
  
set resList to resArray’s ASify() as list
  
  
return resList
  
end diffLists

★Click Here to Open This Script 

AppleScript名:listのdiffをASだけでとる(時間計測用)

script spd
  property aList : {}
  
property bList : {}
end script

set aList of spd to {}
set bList of spd to {}

repeat 1000 times
  set the end of aList of spd to random number from 1 to 1000
  
set the end of bList of spd to random number from 1 to 1000
end repeat

set aRes to diffList(aList of spd, bList of spd) of listDiffKit
–> {{0, 9, 11}, {5}}

script listDiffKit
  
  
–リスト同士のdiffをとる
  
on diffList(aaList, bbList)
    copy {aaList, bbList} to {aList, bList} –fix?
    
set notExistInBlist to {}
    
    
if aList is equal to bList then
      return {{}, {}}
    end if
    
    
repeat with i in aList
      set j to contents of i
      
if j is in bList or j is equal to bList then
        set bList to deleteSpecifiedItemFromList(bList, j) of me
      else
        set the end of notExistInBlist to j
      end if
    end repeat
    
    
return {notExistInBlist, bList}
  end diffList
  
  
–指定内容の要素をリストから削除して返す
  
on deleteSpecifiedItemFromList(aList, anItem)
    set iCount to 1
    
repeat with i in aList
      set j to contents of i
      
if j = anItem then
        set aaList to oneItemDelete(aList, iCount) of me
        
return aaList
      end if
      
set iCount to iCount + 1
    end repeat
    
    
return aList
    
  end deleteSpecifiedItemFromList
  
  
–リスト中の指定要素を削除して返す
  
on oneItemDelete(aList, chgNum)
    set newList to {}
    
set aLen to length of aList
    
    
if chgNum = 1 then
      set aLen to length of aList
      
if aLen > 1 then
        set maeList to items 2 thru aLen of aList
        
set newList to maeList
      else
        set newList to {}
      end if
    else if chgNum = aLen then
      set maeList to items 1 thru (aLen - 1) of aList
      
set newList to maeList
      
    else
      set maeList to items 1 thru (chgNum - 1) of aList
      
set atoList to items (chgNum + 1) thru -1 of aList
      
set newList to maeList & atoList
    end if
    
    
return newList
  end oneItemDelete
  
  
on retDelimedText(aList, aDelim)
    set aText to “”
    
set curDelim to AppleScript’s text item delimiters
    
set AppleScript’s text item delimiters to aDelim
    
set aText to aList as text
    
set AppleScript’s text item delimiters to curDelim
    
return aText
  end retDelimedText
  
  
–文字置換ルーチン
  
on repChar(origText, targStr, repStr)
    set {txdl, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, targStr}
    
set temp to text items of origText
    
set AppleScript’s text item delimiters to repStr
    
set res to temp as text
    
set AppleScript’s text item delimiters to txdl
    
return res
  end repChar
end script

★Click Here to Open This Script 

2014/10/30 ASからASOCのハンドラを呼び出す際には

昨日の問題の解決・・・小数を含む数値のリストをASOC(「AppleScriptObjC」あるいは「AppleScript/Objective-C」と呼ばれる)のハンドラに渡してソートさせた場合に、小数を含む値に丸め誤差が発生するという問題についてです。

これまでにも、Xcode上でASOCのプログラム(GUIベースのアプリケーション)は作ってきましたが、ASOCのハンドラ同士で呼び出しを行う際には極力文字列でデータをやりとりし、AppleScript側からASOC側を呼び出すことはしてきませんでした。

OS X 10.9までは、スクリプトエディタ上でもASOCのプログラムは書けたものの、あくまでアプレット上で完全にプログラムが分断された状態で動いていたために、見えてこなかった問題点でもあります。

つまり、この問題はOS X 10.10で1本のScript中で通常のAppleScriptとASOCが混在する状況が生まれたために見えてきた問題ともいえます(個人的に、OS X 10.9までのScript Editor上で記述するASOC(Interface BuilderでGUIが作れない)にあまり魅力を感じていなかったので、全然使っていなかったし)。

xcode.png

# Xcode上でも「小数点を含む数値リスト」を処理した場合には、同様の問題が出ました。Scripting Bridgeそのもののバグっぽいですね。Appleにバグレポートを書いて担当者を説得するにも時間がかかるので、目下解決策を検証中です。解決はしたのですが、自分ひとりだけでは済まないので、、、

調査したところ、list→NSArrayの型変換では問題は発生していないようでしたが、ASOCのハンドラからNSArray→listの型変換を行って値を返す際に問題が発生していました。

NSArray→listの型変換そのものはScripting Bridgeの処理系が行っているため、現状ではどーーにもなりません(Scripting Bridgeのバグ)が、「数値リスト」ではなく「数字のテキストのリスト」を扱うようにすれば、数値リストの型変換にともなう丸め誤差の発生を回避できます。

つまり、数値文字列のリストをASOC側に渡して、ソーティング(大小比較)自体を「数値として評価」すればOK。

というわけで、ASOC側には「数値リスト」ではなく「数字の文字列リスト」を渡し、ASOC側でそれぞれの要素を「数値として大小比較」するようにしてみました。念のため、有効桁数の多いfloatValueとして数値評価させています。

だいたい、AppleScriptObjCでプログラムを組む場合には、User Interface系をAppleScriptObjCで実装し、メインロジック部分は別途「通常のAppleScript」で組むことで、メンテナンス性を高めつつ、使いやすさを向上させる・・・といったケースが多いところです。

このため、AppleScriptObjCからAppleScriptを呼び出す場合、メニューやラジオボタンのID(整数)であったり、ファイルのパス(文字列)であったりと、今回の問題にひっかからない利用の仕方がほとんどでした。

OS X 10.10の「通常のAppleScriptの中にAppleScriptObjCを書けるようにする」という拡張により、これまでに少なかった「AppleScriptからAppleScriptObjCの機能を利用し、値を受け取る」という処理パターンが増え、問題点が露見したのでしょう。

AppleScript名:asoc_sorting_number_list_v2
use AppleScript version “2.4″
use framework “Foundation”
use scripting additions

set aList to {“-1.1″, “1″, “10″, “0.1″, “1.1″, “1.12″, “-1″, “-100″} –Original List
set aRes to sort1DNumList_ascOrder_(aList, true)
–> {”-100″, “-1.1″, “-1″, “0.1″, “1″, “1.1″, “1.12″, “10″}–sort ascending

set bRes to sort1DNumList_ascOrder_(aList, false)
–> {”10″, “1.12″, “1.1″, “1″, “0.1″, “-1″, “-1.1″, “-100″}–sort descending

–Sort 1-Dimension List(String Number List)
on sort1DNumList:theList ascOrder:aBool
  tell current application’s NSSet to set theSet to setWithArray_(theList)
  
tell current application’s NSSortDescriptor to set theDescriptor to sortDescriptorWithKey_ascending_(“floatValue”, aBool)
  
set sortedList to theSet’s sortedArrayUsingDescriptors:{theDescriptor}
  
return (sortedList) as list
end sort1DNumList:ascOrder:

(*
–Sort 1-Dimension List(Number List)
on sort1DNumList2:theList ascOrder:aBool
  set anArray to current application’s NSArray’s arrayWithArray:theList
  set sortedList to anArray’s sortedArrayUsingSelector:(”numberCompare:”)
  return (sortedList) as list
end sort1DNumList2:ascOrder:
*)

–Sort 1-Dimension List(String List)
on sort1DList:theList ascOrder:aBool
  set aDdesc to current application’s NSSortDescriptor’s sortDescriptorWithKey:“self” ascending:aBool selector:“localizedCaseInsensitiveCompare:”
  
set theArray to current application’s NSArray’s arrayWithArray:theList
  
return (theArray’s sortedArrayUsingDescriptors:{aDdesc}) as list
end sort1DList:ascOrder:

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2014/10/29 AppleScriptからASOCのソートルーチンを利用する上での注意事項

OS X 10.10で一般のAppleScriptとASOCを普通にまじえて記述できるようになったため、いろいろと試してみました。

すると、ソートについていろいろと注意すべき点がわかってきたのでまとめてみます。

文字列のソート順序が違う

ためしにさまざまな文字を与えて並び順を調べてみたら、微妙に違うことがわかりました。

テストデータとして、

set aList to {”ん”, “ば”, “は”, “ぱ”, “あ”, “ま”, “ぁ”, “ア”, “か”, “ァ”}

のようなデータを用意し、昇順ソートを指定した際に、

AS: {”あ”, “ァ”, “ぁ”, “ア”, “か”, “は”, “ば”, “ぱ”, “ま”, “ん”}
ASOC:{”あ”, “ぁ”, “ア”, “ァ”, “か”, “は”, “ば”, “ぱ”, “ま”, “ん”}

と、文字の並び順が微妙に異なります。ASOC側でもうちょっとソートのパラメータを指定すると結果が変わったりしてきそうですが、とりあえず現状はこんな感じです。

どちらかといえば、ASだけで行うソートの方に不自然さを感じるぐらいですし、いまどき半角カタカナでもないでしょうから無視できそうですが・・・問題は次です。

小数を含む数値リストをソートすると丸め誤差が出る

小数を含む数値のリスト、

set aList to {1, 1, 10, 0.1, 1.1, -1, -100}

をデータとして与えてソートしてみたところ、返ってきた結果は、

–> {-100, -1, 0.10000000149, 1, 1.100000023842, 10}

微妙に値が変わってしまいました

回避策についてはいろいろ調べていますが、(US AppleのAppleScript Users MLに久しぶりに投稿してShane Stanleyに教えてもらいました)小数の値を含む数値リストのやりとりをするのは得策ではなさそうな雰囲気です(いまのところ)。

少なくとも、ASから数値をASOCのハンドラに渡しただけでは変わらないようです。

いろいろ試してみたところ、ハンドラ側でNSNumberに変換して処理を行い、結果を戻すさいに「as number」とか「as real」とかで型変換して返すときに丸め誤差が出てしまう模様です。

数値のパラメータであれば、ASから数値をASOCハンドラに渡して、丸め誤差を出さずに返すことはできたのですが、リストに入れてしまうとお手上げの状態。

まだ、試行錯誤を行ってみる必要があるようです。

AppleScript名:asocで1D Listをソート
use AppleScript version “2.4″
use framework “Foundation”
use scripting additions

–昇順ソート(ASOC)
set aList to {“ん”, “ば”, “は”, “ぱ”, “あ”, “ま”, “ぁ”, “ア”, “か”, “ァ”}
set aRes to sort1DList_ascOrder_(aList, true)
–> {”あ”, “ぁ”, “ア”, “ァ”, “か”, “は”, “ば”, “ぱ”, “ま”, “ん”}

–降順ソート(ASOC)
set bRes to sort1DList_ascOrder_(aList, false)
–> {”ん”, “ま”, “ぱ”, “ば”, “は”, “か”, “あ”, “ぁ”, “ア”, “ァ”}

–昇順ソート(AppleScript)
set cRes to shellSortAscending(aList)
–> {”あ”, “ァ”, “ぁ”, “ア”, “か”, “は”, “ば”, “ぱ”, “ま”, “ん”}

–昇順ソート(AppleScript)
set dRes to shellSortDescending(aList)
–> {”ん”, “ま”, “ぱ”, “ば”, “は”, “か”, “ぁ”, “ア”, “あ”, “ァ”}

set aList to {“1″, “01″, “10″, “000.1″, “1.1″, “-1″, “-100″}
set aRes to sort1DList_ascOrder_(aList, true)
–> {”-1″, “-100″, “000.1″, “01″, “1″, “1.1″, “10″}

set aList to {1, 1, 10, 0.1, 1.1, -1, -100}
set aRes to sort1DNumList_ascOrder_(aList, true)
–> {-100, -1, 0.10000000149, 1, 1.100000023842, 10}

–1D List(数値)をsort / ascOrderがtrueだと昇順ソート、falseだと降順ソート
on sort1DNumList:theList ascOrder:aBool
  tell current application’s NSSet to set theSet to setWithArray_(theList)
  
tell current application’s NSSortDescriptor to set theDescriptor to sortDescriptorWithKey_ascending_(missing value, true)
  
set sortedList to theSet’s sortedArrayUsingDescriptors:{theDescriptor}
  
return (sortedList) as list
end sort1DNumList:ascOrder:

–1D List(文字)をsort / ascOrderがtrueだと昇順ソート、falseだと降順ソート
on sort1DList:theList ascOrder:aBool
  set aDdesc to current application’s NSSortDescriptor’s sortDescriptorWithKey:“self” ascending:aBool selector:“localizedCaseInsensitiveCompare:”
  
set theArray to current application’s NSArray’s arrayWithArray:theList
  
return (theArray’s sortedArrayUsingDescriptors:{aDdesc}) as list
end sort1DList:ascOrder:

–入れ子ではないリストの昇順ソート
on shellSortAscending(aSortList)
  script oBj
    property list : aSortList
  end script
  
set len to count oBj’s list’s items
  
set gap to 1
  
repeat while (gap len)
    set gap to ((gap * 3) + 1)
  end repeat
  
repeat while (gap > 0)
    set gap to (gap div 3)
    
if (gap < len) then
      repeat with i from gap to (len - 1)
        set temp to oBj’s list’s item (i + 1)
        
set j to i
        
repeat while ((j gap) and (oBj’s list’s item (j - gap + 1) > temp))
          set oBj’s list’s item (j + 1) to oBj’s list’s item (j - gap + 1)
          
set j to j - gap
        end repeat
        
set oBj’s list’s item (j + 1) to temp
      end repeat
    end if
  end repeat
  
return oBj’s list
end shellSortAscending

–入れ子ではないリストの降順ソート
on shellSortDescending(aSortList)
  script oBj
    property list : aSortList
  end script
  
set len to count oBj’s list’s items
  
set gap to 1
  
repeat while (gap len)
    set gap to ((gap * 3) + 1)
  end repeat
  
repeat while (gap > 0)
    set gap to (gap div 3)
    
if (gap < len) then
      repeat with i from gap to (len - 1)
        set temp to oBj’s list’s item (i + 1)
        
set j to i
        
repeat while ((j gap) and (oBj’s list’s item (j - gap + 1) < temp))
          set oBj’s list’s item (j + 1) to oBj’s list’s item (j - gap + 1)
          
set j to j - gap
        end repeat
        
set oBj’s list’s item (j + 1) to temp
      end repeat
    end if
  end repeat
  
return oBj’s list
end shellSortDescending

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

AppleScript名:asocで少数を含む数値を誤差のない形式でASに返す
–By Shane Stanley

use AppleScript version “2.4″
use framework “Foundation”
use scripting additions

set e to 0.1
set f to numberFloatWith_(e)
–> 0.1

on numberFloatWith:aNum
  set theNum to current application’s NSNumber’s numberWithFloat:aNum
  
return (theNum’s descriptionWithLocale:(current application’s NSLocale’s systemLocale())) as real
end numberFloatWith:

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に