我正在尝试生成类似于以下内容的内容:
鉴于HINTS = ["a", "s", "d", "f", "g", "h", "j", "k", "l", ";"]
,allHints(21)
应该提供类似于:
["a", "s", "d", "f", "g", "h", "j", "k", "l", ";", "aa", "as", "ad", "af", "ag", "ah", "aj", "ak", "af"..."sa", "ss", "sd"...]
也就是说,所有元素一个接一个地连接在一起以进行单独组合。如果可能的话,我想用某种递归来写这个,因为这似乎是一个倾向于以这种方式解决的问题。
我的解决方案是嵌套两个for
循环迭代每个组合9(考虑到有多少提示),但它似乎在第二次被困在某处。我不太熟悉Coffeescripts for
语法,但我尝试过类似的东西:
allHints = ->
for i in [0...anchors]
do (i) ->
if i > 9
(for y in [0...i % 9]
do (y) ->
#changing this to HINTS[Math.round(i / 10)] as it should be produces weird results
HINTS[y] + HINTS[i % 9 - 1])[0]
else
HINTS[i]
console.log allHints 19
但不幸的是,这为最后一个元素提供了undefined
。任何人都可以帮我弄清楚如何正确的for循环生成一个数组?这是a gist供参考。
答案 0 :(得分:4)
一种有点惯用的CoffeeScript解决方案:
HINTS = ["a", "s", "d", "f", "g", "h", "j", "k", "l", ";"]
allHints = (n) ->
HINTS.concat(((b + a for a in HINTS) for b in HINTS)...)[0...n]
然后allHints(12)
返回['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', 'aa', 'as']
。
第一个splat(...
)将嵌套推导创建的2D数组转换为concat()
的1D数组参数列表。
这个解决方案显然效率不高,因为它只会丢弃任何不需要的所有排列。
答案 1 :(得分:0)
听起来你基本上想要一个双嵌套循环,每次迭代每个字符时迭代每个字符,在这种情况下你也可以使用HINTS数组的长度而不用费心自己计算东西。
这是怎么回事?
var HINTS = ["a", "s", "d", "f", "g", "h", "j", "k", "l", ";"]
function allhints() {
var all = Array(); // Create a new array
all = all.concat(HINTS); // Add the individual hints
for (var i=0; i<HINTS.length; i++) // for each character in HINTS
for (var j=0; j<HINTS.length; j++) // with each character in HINTS
all.push(HINTS[i] + HINTS[j]); // Append the two combined hint characters
return all;
}
这不是递归的,但无论如何递归并没有真正帮助。它还给出了您描述的所需结果,但没有任何长度限制。如果您确实想限制结果,可以像这样定义所有提示:
function allhints(n) {
var all = Array(); // Create a new array
all = all.concat(HINTS); // Add the individual hints
for (var i=0; i<HINTS.length; i++) // for each character in HINTS
for (var j=0; j<HINTS.length && all.length < n; j++) // with each character in HINTS
all.push(HINTS[i] + HINTS[j]); // Append the two combined hint characters
return all.slice(0,n);
}
所以allhints(4)只返回[“a”,“s”,“d”,“f”]。
答案 2 :(得分:0)
您真正想要解决的问题是“如何生成集合的所有子集”,特别是“如何生成给定数组HINTS
的所有子集”。
最简单的方法是考虑集合中的每个元素都可以映射到二进制字符串。您的数组HINTS有10个元素,因此要查找所有子集,我们只需要以二进制计数从0000000000到1111111111,然后选择我们去的任何元素(例如,0000000101将是“k;”)。
以下代码几乎完成;我看了一下它似乎有一个错误(我会看看以后是否可以调试它。)
HINTS = ["a", "s", "d", "f", "g", "h", "j", "k", "l", ";"]
var results = [];
var binCounter;
var hint;
for ( var i = 0; i < Math.pow(2, HINTS.length); i++) {
binCounter = i.toString(2); //convert the number to binary
hint = "";
//generate the hint
for ( var j = 0; j < binCounter.length; j++) {
//if the boolean digit was true, pick the corresponding element from our set
if (binCounter[j] == 1) {
hint += HINTS[j];
}
}
results.push(hint);
}
console.log(results);
答案 3 :(得分:0)
问题似乎确实是生成给定集合的可能子集的集合。有时被称为集合的幂集。
基本上有3种可能的解决方案: 1)二项式系数。见http://en.wikipedia.org/wiki/Binomial_coefficient 可以在Pyton的itertools中找到一个实现。二项式系数为您提供一定长度的子集。如果将长度为0的子集组合到原始集的长度,则完成。
2)一种递归算法,可以在几代中“增长”子集。见京都的答案。请参阅下面的更详细的版本。维基百科文章提到帕斯卡的三角形,这是对这种算法的暗示
3)元素是否在子集中。这意味着存在2 ^(集合的长度)子集。 每个子集可以被编码为具有子集数字长度的二进制数。 这是在NT3RP的答案中完成的。您也可以使用一个布尔数组而不是字符串。我在下面发布了我的C#版本。
基于Miranda中的实现,我在coffeescript中的Powerset递归版本。 (我想知道我是否可以在Coffeescript中将其编码为与Miranda一样紧凑,然后我发现了这个问题)
在米兰达的powerset
powerset [] = [[]]
powerset (x:xs) = [[x] ++ y | y <- ys] ++ ys
where ys = powerset xs
powerof in coffeescript:
powerset = (zs) ->
if zs.length is 0
[[]]
else
[x,xs...]=zs
ys=powerset xs
result=([x].concat y for y in ys).concat ys
# number of elements in powerset is 2^length of the powerset
res=powerset [1,2,3,4,5,6,7,8,9,10]
console.log res
console.log "length:" +res.length
我对这一切的兴趣:
我编写了一个用于生成的二进制数方法的C#实现 不久前的子集。为了好玩,我还想写一个“增长”子集的版本。
我知道Miranda是一种非常简洁的函数式编程语言。我想知道coffeescript是否允许与succinctnes相同的水平。我无法在Scala,F#或Clojure中实现这一目标。我无法在coffeescript中做到这一点,但“京都”展示了它是如何完成的。
在C#版本下面作为IEnumerable。它生成子集中的元素元组和所有其他元素。
...
//imports and house keeping removed
private static IEnumerable<Tuple<IList<T>,IList<T>>> SubsetImpl<T>(this IList<T> argList){
int elementCount=argList.Count;
int bits=(1<<elementCount);//2 to the power of elementCount
List<Tuple<IList<T>,IList<T>>> subsets=new List<Tuple<IList<T>, IList<T>>>(bits);
for(int i=0;i<bits;i++){
int[] mask={i};
BitArray flags=new BitArray(mask);
IList<T> incomb=new List<T>();
IList<T> outcomb=new List<T>();
for(int j=0;j<argList.Count;j++){
if( flags[j]){
incomb.Add(argList[j]);
}else{
outcomb.Add(argList[j]);
}
}
Tuple<IList<T>,IList<T>> t=new Tuple<IList<T>,IList<T>>(incomb,outcomb);
subsets.Add(t);
}
return subsets;
}
...
答案 4 :(得分:0)
一个简单的解决方案:
allHints = (n) ->
ln = hints.length
# return sliced array if n is less than it's length
return hints.slice(0, n) if n <= ln
# clone the array, find number of possible combinations
clone = hints.slice()
limit = Math.min(n, ln*ln)
# add the combinations up to the requested length or limit
for i in [ln...limit]
clone[i] = hints[Math.floor(i / ln) - 1] + hints[i % ln]
return clone
这可以优化为不使用嵌套循环每次都查找基本字符,但为了清楚起见,保留原样。