随着元素数量的增加,循环遍历所有字符组合

时间:2016-07-29 10:43:20

标签: arrays string matlab loops

我想要实现的目标:

我有一个函数,我想循环遍历可打印的ascii字符的所有可能组合,从单个字符开始,然后是两个字符,然后是三个等。

让我感到困难的部分是,我希望这能够为尽可能多的角色工作(留在一夜之间)。

对于记录:我知道abc确实是97 98 99,因此如果更容易,数字表示就可以了。

这适用于少数字符:

可以创建n个字符的所有可能组合的列表,然后循环遍历它,但是在n = 4时需要大量内存。 n > 5(至少在普通台式计算机上)这种方法实际上是不可能的。

在下面的脚本中,我所做的就是为每个组合增加一个计数器。我真正的功能做了更高级的东西。

如果我有无限的记忆力,我可以做(感谢Luis Mendo):

counter = 0;
some_function = @(x) 1;
number_of_characters = 1;
max_time = 60;
max_number_of_characters = 8;
tic;
while toc < max_time && number_of_characters < max_number_of_characters
    number_of_characters = number_of_characters + 1;
    vectors = [repmat({' ':'~'}, 1, number_of_characters)];
    n = numel(vectors);
    combs = cell(1,n);
    [combs{end:-1:1}] = ndgrid(vectors{end:-1:1});
    combs = cat(n+1, combs{:});
    combs = reshape(combs, [], n);
    for ii = 1:size(combs, 1)
        counter = counter + some_function(combs(ii, :));
    end
end

现在,我希望在一定的时间内,5秒,10秒,2分钟,30分钟内尽可能多地循环组合,所以我希望创建一个功能“s”仅限于可用时间,并且仅使用一些合理的内存量。

尝试为更多角色做出(并失败):

我考虑使用上述方法之一预先计算两个或三个字母的组合,并仅对最后一个字符使用循环。这不需要太多内存,因为它只有一个(相对较小的)数组,加上一个或多个循环的附加字符。

我设法将其扩展到最多4个字符,但除此之外,我开始遇到麻烦。

我试图使用一个向上计数的迭代器。每当我点击any(mod(number_of_ascii .^ 1:n, iterator) == 0)时,我都会将第m个字符加1。因此,最后一个字符只重复周期!"# ... ~,每次点击波形时,第二个字符递增。每当第二个字符出现波形时,第三个字符会递增等。

您对我如何解决这个问题有什么建议吗?

2 个答案:

答案 0 :(得分:0)

看起来你基本上试图计算基数为26(或者如果你需要CAPS则为52)。该基数中的每个数字都将考虑特定的字符串。例如,

0,1,2,3,4,5,6,7,8,9,A,B,C,d,E,F,G,H,I,J,K,L,M,N ,O,p,10,11,12,...

这里,上限A到P只是用于表示base-26系统的数字符号的符号。以上只是代表这一串字符。

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,BA,BB,BC,...

然后,你可以这样做:

symbols = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E',...
        'F','G','H','I','J','K','L','M','N','O','P']
characters = ['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']
count=0;
  while(true)
     str_base26 = dec2base(count,26)
     actual_str = % char-by-char-lookup-of-str26 to chracter string
     count=count+1;
  end

当然,它不代表以0结尾开头的字符。但那应该很简单。

答案 1 :(得分:0)

你对于只是获得一个向上计数的迭代器的想法并不是很远。

这个想法需要的是从整数到ASCII字符的映射。正如StewieGriffin建议的那样,你只需要在基数95(94个字符加空格)中工作。

为什么是空白:您需要将某些内容映射到0并与之等效。空白是完美的候选人。然后,您只需跳过包含任何空格的字符串。如果您不这样做并直接从!开始,则您将无法代表!!!ab等字符串。

首先让我们定义一个将(1:1)整数映射到字符串的函数:

function [outstring,toskip]=dec2ASCII(m)


    out=[];

    while m~=0

        out=[mod(m,95) out];

        m=(m-out(1))/95;

    end

    if any(out==0)

        toskip=1;

    else

        toskip=0;

    end

    outstring=char(out+32);

end

然后在您的主脚本中

counter=1;
some_function = @(x) 1;
max_time = 60;
max_number_of_characters = 8;
currString='';


tic;


while numel(currString)<=max_number_of_characters&&toc<max_time

    [currString,toskip]=dec2ASCII(counter);

    if ~toskip

        some_function(currString);

    end

    counter=counter+1;

end

dec2ASCII函数的一些随机输出:

dec2ASCII(47)

ans =

O

dec2ASCII(145273)

ans =

0)2

就性能而言,我无法详细阐述,因为我不知道你想对你的some_function做些什么。我唯一可以说的是dec2ASCII的运行时间大约为2*10^(-5) s

旁注:这样的迭代在速度方面会非常有限。如果函数some_function什么都不做,你就可以在大约40分钟内循环显示4个字符,而5个字符最多需要64个小时。也许你想减少想要通过你迭代的函数传递的东西数量。

但是,此代码很容易并行化,因此如果您想检查更多组合,我建议您尝试以并行方式执行此操作。