编程智慧表明,将循环编程任务转变为线性编程任务(矢量化)可以缩短计算时间。 但这是真的吗? 在什么条件下? 多少? 挑战 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 );