程式設計智慧表明,將循環程式設計任務轉變為線性程式設計任務(向量化)可以縮短計算時間。但這是真的嗎?在什麼條件下?多少?挑戰 1 提供了一個很好的機會來找出答案。為了回答這四個挑戰問題,我決定每組七個字母,我會:
- 計算每個字母在字典單字中出現的次數。這讓我找到了第 2、3 和 4 項的答案。
- 確定一個單字是否包含不在七個字母集中的字母。這是第 1 項所需要的。
挑戰 1 嘗試 1.JSL使用基於Length和Regex函數的列公式進行計數。使用了一些附加的列公式以使程式碼更易於閱讀。唯一的循環用於重新評估每個字母集的函數。運行時間略低於 29 秒(所有時間均為 10 次運行的平均值)。不錯,但也不是很好。是公式的複雜性還是因為公式評估應該使用循環(在列表或矩陣上)而不是列來完成?我使用test simple.JSL和test full.JSL進行調查。除了比較列與循環之外,我還想看看直接從表或列表中讀取輸入值是否更快。第一次將表中的值讀取到列表或矩陣中是否會增加時間?
以下的結果(以秒為單位)表明,隨著公式變得更加複雜,公式和循環之間的差異越來越不明顯。用於建立公式的函數對時間的影響要大得多。常規搜尋函數( Regex和Loc )比特定搜尋函數( Contains和Substr )慢得多。
|
功能
|
公式
|
列表+列表訪問
|
列表+表訪問
|
|
長度
|
0.0525
|
0.1398
|
0.1311
|
|
地方 + 專案
|
0.4187
|
0.5462
|
0.5383
|
|
Length + 正規表示式
|
9.3744
|
9.2745
|
9.3911
|
|
循環+包含+子字串
|
3.3255
|
3.4139
|
3.5444
|
將這些知識付諸實踐,我創建了兩個新腳本。挑戰 1 嘗試 2.JSL使用公式中包含一個循環的公式來計算字母數。挑戰 2 嘗試 3.JSL使用列表而不是公式。它還利用了這樣的條件:對於滿足第 1、2 和 3 項的任何單詞,它必須至少包含一次所有七個字母組字母。運行時間分別為 15.50 秒和 10.40 秒。在這種情況下,循環可能會更快,因為需要評估的函數更少。這兩種改進都比我最初的嘗試好得多,但仍然不是最快的。改進必須來自更快的函數、更少的循環/函數評估或回答挑戰問題的不同方法。由於前兩種方法似乎不太可能產生富有成效的可能性,因此尋求不同的方法。
挑戰 1 Pattern Matching.JSL腳本來自@Craige_Hales 。 Craige 最近從 JMP Development 退休,但在社區中仍然非常活躍。他負責JMP中的模式匹配和正規表示式功能。 Craige 的解決方案透過首先將字典列表轉換為長字串來向量化問題,然後應用模式匹配將單字解析到解決方案桶中。它的運行時間為 3.71 秒,提供了模式匹配的廣度和靈活性的一個很好的例子。最快的解決方案來自@brady_brady ,耗時 2.76 秒。他沒有將每個字母集應用於字典單詞,而是先計算每個字典單字中每個字母的出現次數。雖然這最初將字母比較的數量從 7 個增加到 26 個,但只需要進行一次,從而避免了對每個新字母集的重新評估。透過從初始字母矩陣中提取適當的列來找到答案單詞,從而獲得更快的解決方案。它也是最短的劇本,只有 1146 個字元。
這是第一次挑戰後的排行榜:
請繼續關注 5 月 1 日推出的挑戰 2!
@MathStatChem在計算字元數之前,我刪除了註解和空格。 在當前狀態下,您的新腳本在我的電腦上運行大約需要 3.6 秒。 比布雷迪慢,但比克雷奇快。 一些小的改變就帶來了相當大的差異! 不過,有些問題的答案不正確。 以下是我使用的字母集以及答案。
//acehlot
1. {"acacatechol"}
2. {"scientificophilosophical"}
3. {"hypercivilization"}
4. {"macracanthrorhynchiasis", "pancreaticoduodenostomy", "pericardiomediastinitis"}
//ilosuvx
1. {"lixivious"}
2.{"subclavioaxillary"}
3.{"excitovascular"}
4. {"formaldehydesulphoxylate"}
//mnoruwy
1.{"unwormy"}
2.{"countrywoman", "journeywoman", "laundrywoman"}
3.{"jurywoman"}
4.{"formaldehydesulphoxylate"}
新舊腳本的長度分別為 2461 和 2469。
所以我使用了與@brady_brady ,但我最初的字母計數程式碼效率非常低,使用了更多循環和對列表的呼叫。我替換了他的方法,果然我的腳本運行了大約 3 秒。很酷!
函數 items() 對此至關重要。我沒有意識到它會這樣做。將字串轉換為其各個字元的列表(按順序,重複的字母作為列表中的單獨項目),只需
項目(字串);
所以 items("easypeasy","") 回傳 {"e", "a", "s", "y", "p", "e", "a", "s", "y"}。
然後使用 contains 來引用字母表字母的索引也是一個非常好的技巧。
contains("abcedfghijklmnopqrstuvwxyz","a") 回傳 1,
contains("abcedfghijklmnopqrstuvwxyz","b") 回傳 2, ...
我使我的程式碼和日誌輸出更加詳細,不確定您是否在計算字元之前刪除了註釋。
這是我的程式碼(使用更快的方法進行了改進):
startTime = Time Of Day( Today() );
letterSetList = {"apouter", "abdcefl", "acouter", "rstlneo", "efghijk"};
alphabet = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x",
"y", "z"};
abet="abcedfghijklmnopqrstuvwxyz";
_dt = Current Data Table();
numwords = N Rows( _dt );
_c = Column( _dt, "Words" );
wordlist = _c << get values;
// get lengths of each word in word list
// also create a matrix indicating how many times each letter in the alphabet is used in each word
wordlengths = J( numwords, 1, 0 );
alphacounts = J( numwords, 26, 0 );
For( ii = 1, ii <= numwords, ii++,
its=items(wordlist[ii],"");
wordlengths[ii] = Length( wordlist[ii] );
for(jj=1, jj<=nitems(its), jj++, alphacounts[ii,contains(abet,its[jj])]++);
);
// also create a matrix indicating if a letter in the alphabet is used in each word
alphaindex = alphacounts > 0;
For( ll = 1, ll <= N Items( letterSetList ), ll++,
str = letterSetList[ll];
// create an indicator vector for the letters in the string
str_alphaindex = J( 1, 26, 0 );
For( jj = 1, jj <= 26, jj++,
For( kk = 1, kk <= Length( str ), kk++,
str_alphaindex[1, jj] = str_alphaindex[1, jj] + (Substr( str, kk, 1 ) == alphabet[jj])
)
);
// 1 The longest word using all seven letters and only those seven letters. Letters may be used more than once.
// words that meet this criteria will have a "zero distance" from their letter indicator row and the string letter indicator vector
pickrow1 = Distance( alphaindex, str_alphaindex ) == 0;
// now find the word that has the longest length
pickrow1 = pickrow1 & (wordlengths == Max( wordlengths[Loc( pickrow1 )] ));
Print( "1. Find longest word(s) that uses only the letters <" || str || "> (item " || Char( ll ) || " from itemSetList)" );
If( Dim( Loc( pickrow1 ) )[1],
Print( wordlist[Loc( pickrow1 )] );
Print( "which is in the following row(s) from the Word List table " );
Print( Loc( pickrow1 & (wordlengths == Max( wordlengths[Loc( pickrow1 )] )) ) );
,
Print( "no word(s) found" )
);
Print( "-------------------" );
// 2 The longest word using all seven letters and any other letters.
// words that meet this condition, the sum of their letter indictor rows for the letters in the string should equal 7
pickrow2 = (V Sum( alphaindex[0, Loc( str_alphaindex )]` )` == 7);
// now find the word that has the longest length
pickrow2 = pickrow2 & (wordlengths == Max( wordlengths[Loc( pickrow2 )] ));
Print(
"2. Find longest word(s) that use all letters <" || str || "> (item " || Char( ll ) ||
" from itemSetList) and/or any other letters"
);
If( Dim( Loc( pickrow2 ) )[1],
Print( wordlist[Loc( pickrow2 )] );
Print( "which is in the following row(s) from the Word List table " );
Print( Loc( pickrow2 ) );
,
Print( "no word(s) found" )
);
Print( "-------------------" );
// 3 The longest word using all seven letters and any other letters where no letter
// from the set of seven is used more than once.
// words that meet this condition, meet the condition for the 2nd rule but also the sum of their letter counts for
// the letters in the string has to be equal to 7
pickrow3 = (V Sum( alphaindex[0, Loc( str_alphaindex )]` )` == 7) & (V Sum( alphacounts[0, Loc( str_alphaindex )]` )` == 7);
// now find the word that has the longest length
pickrow3 = pickrow3 & (wordlengths == Max( wordlengths[Loc( pickrow3 )] ));
Print(
"3. Find longest word(s) that use all letters <" || str || "> (item " || Char( ll ) ||
" from itemSetList) only once and/or any other letters "
);
If( Dim( Loc( pickrow3 ) )[1],
Print( wordlist[Loc( pickrow3 )] );
Print( "which is in the following row(s) from the Word List table " );
Print( Loc( pickrow3 ) );
,
Print( "no word(s) found" )
);
Print( "-------------------" );
// 4 The longest word in which 5 of the 7 letters appears.
// Any letter including those outside of the 7 may appear once or more
// except the two unused letters from the list of 7, which may not appear at all.
// words that meet this condition have the sum of their letter indicators (for the letters in the string) equal to 5
pickrow4 = (V Sum( alphaindex[0, Loc( str_alphaindex )]` )` == 5);
// now find the word that has the longest length
pickrow4 = pickrow4 & (wordlengths == Max( wordlengths[Loc( pickrow4 )] ));
Print(
"4. Find longest word(s) that uses only 5 of the 7 letters <" || str || "> (item " || Char( ll ) ||
" from itemSetList) and/or any other letters"
);
If( Dim( Loc( pickrow4 ) )[1],
Print( wordlist[Loc( pickrow4 )] );
Print( "which is in the following row(s) from the Word List table " );
Print( Loc( pickrow4 ) );
,
Print( "no word(s) found" )
);
Print( "-------------------" );
);
endTime = Time Of Day( Today() );
Print( endTime - startTime );