首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何计算一系列字符的笛卡尔幂?

如何计算一系列字符的笛卡尔幂?
EN

Stack Overflow用户
提问于 2013-06-11 16:57:48
回答 4查看 267关注 0票数 5

我想做一个函数,它能够使用a-z,0-9生成字母和可选数字的列表。

代码语言:javascript
复制
$output = array();
foreach(range('a','z') as $i) {
    foreach(range('a','z') as $j) { 
        foreach(range('a','z') as $k) { 
            $output[] =$i.$j.$k;
        }
    }
}

谢谢

示例:

代码语言:javascript
复制
 myfunction($include, $length)

用法类似于:

代码语言:javascript
复制
 myfunction('a..z,0..9', 3);

输出:

代码语言:javascript
复制
000
001
...
aaa
aab
...
zzz

输出将包含字母和数字的所有可能组合。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-06-11 18:12:04

设置舞台

首先,使用range将诸如"0..9"之类的字符串扩展为"0123456789"

代码语言:javascript
复制
function expand_pattern($pattern) {
    $bias = 0;
    $flags = PREG_SET_ORDER | PREG_OFFSET_CAPTURE;
    preg_match_all('/(.)\.\.(.)/', $pattern, $matches, $flags);
    foreach ($matches as $match) {
        $range = implode('', range($match[1][0], $match[2][0]));
        $pattern = substr_replace(
            $pattern, 
            $range, 
            $bias + $match[1][1],
            $match[2][1] - $match[1][1] + 1);
        $bias += strlen($range) - 4; // 4 == length of "X..Y"
    }

    return $pattern;
}

它可以处理任意数量的可扩展模式,并注意保持它们在源字符串中的位置,例如

代码语言:javascript
复制
expand_pattern('abc0..4def5..9')

将返回"abc01234def56789"

一次计算所有结果

现在我们可以轻松地进行扩展了,下面是一个函数,它计算给定一个允许字符串和一个长度的笛卡尔乘积:

代码语言:javascript
复制
function cartesian($pattern, $length) {
    $choices = strlen($pattern);
    $indexes = array_fill(0, $length, 0);
    $results = array();
    $resets = 0;

    while ($resets != $length) {
        $result = '';
        for ($i = 0; $i < $length; ++$i) {
            $result .= $pattern[$indexes[$i]];
        }
        $results[] = $result;

        $resets = 0;
        for ($i = $length - 1; $i >= 0 && ++$indexes[$i] == $choices; --$i) {
            $indexes[$i] = 0;
            ++$resets;
        }
    }

    return $results;
}

例如,要获得问题中描述的输出,您可以这样做

代码语言:javascript
复制
$options = cartesian(expand_pattern('a..z0..9'), 3);

(我将扩展长度限制为2,这样输出就不会爆炸)。

动态生成结果

由于结果集可能非常大(随着$length呈指数级增长),一次生成结果集可能被证明是令人望而却步的。在这种情况下,可以重写代码,使其依次返回每个值(迭代器样式),这在PHP5.5中由于generators而变得非常简单

代码语言:javascript
复制
function cartesian($pattern, $length) {
    $choices = strlen($pattern);
    $indexes = array_fill(0, $length, 0);
    $resets = 0;

    while ($resets != $length) {
        $result = '';
        for ($i = 0; $i < $length; ++$i) {
            $result .= $pattern[$indexes[$i]];
        }
        yield $result;

        $resets = 0;
        for ($i = $length - 1; $i >= 0 && ++$indexes[$i] == $choices; --$i) {
            $indexes[$i] = 0;
            ++$resets;
        }
    }
}

票数 2
EN

Stack Overflow用户

发布于 2013-06-11 17:48:51

有关生成所有可能组合的代码,请参阅以下答案:https://stackoverflow.com/a/8567199/1800369

您只需要添加$length参数来限制组合的大小。

票数 0
EN

Stack Overflow用户

发布于 2013-06-11 18:22:28

您可以使用递归函数

假设你的意思是它可以是任意数量的层数,你可以使用一个递归函数来生成一个排列数组,例如:

代码语言:javascript
复制
/** 
 * take the range of characters, and generate an array of all permutations
 *
 * @param array $range      range of characters to itterate over
 * @param array $array      input array - operated on by reference
 * @param int $depth        how many chars to put in the resultant array should be
 * @param int $currentDepth internal variable to track how nested the current call is
 * @param string $prefix    internal variable to know what to prefix the current string with
* @return array             permutations
*/
function foo($range, &$array, $depth = 1, $currentDepth = 0, $prefix = "") {
    $start = !$currentDepth;
    $currentDepth++;

    if ($currentDepth > $depth) {
        return;
    }   

    foreach($range as $char) {
        if ($currentDepth === $depth) {
            $array[] = $prefix . $char;
            continue;
        }   

        foo($range, $array, $depth, $currentDepth, $prefix . $char);
    }   

    if ($start) {
        return $array;
    }

使用上面的函数,初始化返回变量并调用它:

代码语言:javascript
复制
$return = array();
echo implode(foo(range('a', 'z'), $return, 3), "\n");

您的输出将是从aaa到zzz的所有三个字符组合:

代码语言:javascript
复制
aaa
aab
...
zzy
zzz

数值参数决定了函数的递归程度:

代码语言:javascript
复制
$return = array();
echo implode(foo(range('a', 'z'), $return, 1), "\n");
a
b
c
...

Here's a live example

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17040134

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档