編程智慧表明,將循環編程任務轉變為線性編程任務(矢量化)可以縮短計算時間。 但這是真的嗎? 在什麼條件下? 多少? 挑戰 1 提供了一個很好的找出答案的機會。 為了回答這四個挑戰性問題,我決定對於每組七個字母,我會:
- 計算每個字母在字典單詞中出現的次數。 這讓我找到了第 2、3 和 4 項的答案。
- 確定一個單詞是否包含不在七個字母組中的字母。 這是項目 1 所需要的。
挑戰1 try 1.JSL使用基於列公式的計數長度和正則表達式功能。 一些額外的列公式用於使代碼更易於閱讀。 唯一的循環用於重新評估每個字母集的功能。 運行時間不到 29 秒(所有時間都是 10 次運行的平均值)。 不錯,但不是很好。 是公式的複雜性還是因為公式評估應該使用循環(通過列表或矩陣)而不是列來完成? 我用了測試簡單.JSL和完整測試.JSL去弄清楚。 除了比較列與循環之外,我還查看了直接從表或列表中讀取輸入值是否更快。 首先將表中的值讀入列表或矩陣是否會增加時間?
下面的結果(以秒為單位)表明,隨著公式變得越來越複雜,公式和循環之間的區別就不那麼明顯了。 用於構建公式的函數對時間的影響要大得多。 一般搜索功能(正則表達式和位置) 比特定的搜索功能慢得多 (包含和子字符串).
功能
|
公式
|
列表+列表訪問
|
列表+表訪問
|
長度
|
0.0525
|
0.1398
|
0.1311
|
位置+項目
|
0.4187
|
0.5462
|
0.5383
|
長度+正則表達式
|
9.3744
|
9.2745
|
9.3911
|
循環 +包含+子字符串
|
3.3255
|
3.4139
|
3.5444
|
將這些知識付諸實踐,我創建了兩個新腳本。 挑戰1 try 2.JSL使用在一個公式中帶有循環的公式來計算字母。 挑戰 2 嘗試 3.JSL使用列表而不是公式。 它還利用了以下條件:對於滿足第 1、2 和 3 項的任何單詞,它必須至少包含一次所有七個字母集字母。 運行時間分別為 15.50 秒和 10.40 秒。 在這種情況下,循環速度可能更快,因為需要評估的函數更少。 這兩種改進都比我最初的嘗試好得多,但仍然不是最快的。 改進必須來自更快的函數、更少的循環/函數評估或回答挑戰問題的不同方法。 由於前兩種方法似乎不太可能產生富有成效的可能性,因此尋求了一種不同的方法。
這挑戰 1 模式匹配.JSL腳本來自@Craige_Hales . Craige 最近從 JMP Development 退休,但在社區中仍然非常活躍。 他負責模式匹配和正則表達式功能JMP . Craige 的解決方案通過首先將字典列表轉換為長字符串來矢量化問題,然後應用模式匹配將單詞解析到解決方案桶中。 它運行 3.71 秒,是模式匹配的廣度和靈活性的一個很好的例子。 最快的解決方案,耗時 2.76 秒,來自@brady_brady . 他沒有將每個字母集應用於字典單詞,而是首先計算每個字母在每個字典單詞中出現的次數。 雖然這最初將字母比較的數量從 7 個增加到 26 個,但只需要進行一次,避免了對每個新字母集進行重新評估。 通過從初始字母表矩陣中提取適當的列來找到答案詞,從而獲得更快的解決方案。 它也是最短的腳本,只有 1146 個字符。
這是第一次挑戰後的排行榜:
請繼續關注 5 月 1 日推出的挑戰 2!
@MathStatChem在計算字符數之前,我刪除了註釋和空格。 您的新腳本在我的機器上以當前狀態運行大約 3.6 秒。 比 Brady 慢,但比 Craige 快。 一些小的變化相當顯著的差異! 但是,有些項目沒有正確回答。 以下是我使用的字母集以及答案。
//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() 對此非常關鍵。我沒有意識到它會這樣做。將字符串轉換為其單個字符的列表(按順序,重複的字母作為列表中的單獨項),只需
項目(字符串);
所以項目(“easypeasy”,“”)返回{“e”,“a”,“s”,“y”,“p”,“e”,“a”,“s”,“y”}。
然後使用 contains 來引用字母表中字母的索引也是一個非常好的技巧。
包含(“abcedfghijklmnopqrstuvwxyz”,“a”)返回 1,
包含(“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 );