dseguy / data-combinator
数据组合器是一个PHP库,用于组合数据。
Requires
- php: ^7.4 || ^8.0
Requires (Dev)
- friendsofphp/php-cs-fixer: 2.18
- phpunit/phpunit: ^9.0
README
当你想要列出各种数据列表的所有可能的组合时。
例如,从 [[1, 2], [3, 4]]
到
[
[1, 3],
[1, 4],
[2, 3],
[2, 4],
]
此组件允许您通过将每个可能的值与其他值组合来创建大型数据集。
应用场景
- 为命令行工具生成所有可能的组合
- 为传入数据生成所有变体
- 生成结构化数据
安装
使用 Composer,执行永恒的操作
$ composer require dseguy/data-combinator
简单示例
require 'vendor/autoload.php'; use Datacombinator\Matrix; $m = new Datacombinator\Matrix(); $m->addSet('x', [1,2,3]); $m->addSet('y', [4,5,6]); foreach($m as $value) { print_r($value); }
这会生成1、2、3与4、5、6的所有组合,总共9个数组。
(
[x] => 1
[y] => 4
)
Array
(
[x] => 1
[y] => 5
)
Array
(
[x] => 1
[y] => 6
)
...
Array
(
[x] => 3
[y] => 6
)
APIs
- 常见行为 - 公共方法的常见行为
- generate() - 生成一个值
- addConstant() - 添加一个唯一值
- addSet() - 添加一组值
- addLambda() - 调用任意函数生成一个值
- addPermute() - 从列表中创建所有排列
- addCombine() - 从列表中创建所有组合
- addCopy() - 克隆对象而不是按值复制
- addMatrix() - 在矩阵中嵌套矩阵
- addAlias() - 重新使用之前生成的值
- addSequence() - 创建具有不同标识符的值
- setClass() - 选择结果的物体类型:数组、列表或对象
- count() - 估计将要生成的元素数量
- toArray() - 以数组形式返回所有可能的组合
常见行为
公共方法至少需要两个参数;值的名称和实际值或值的生成器。
每个值名称是一个字符串或null。当名称为null时,会自动生成id,从0开始(类似于PHP)。
数组的索引可以用字符串提供,该字符串将被PHP转换为数组索引。使用null和Matrix::TYPE_ARRAY与使用Matrix::TYPE_LIST具有相同的效果。使用Matrix::TYPE_LIST与命名值是合法的:在生成时,名称将被丢弃,但在配置时提供了一些可读性。
可以通过再次添加来覆盖之前设置的属性。
建议避免使用除字符串、字符串中的整数和null以外的任何格式。
addConstant
这向矩阵添加一个唯一值。此值不会有重复。请注意,该值可能是一个数组。
$m = new Datacombinator\Matrix(); $m->addConstant('x', 2); $m->addConstant('y', 3); Array ( [x] => 2 [y] => 3 )
有关克隆对象的更多信息,请参阅 addCopy()。
generate
返回一个用于foreach()结构的生成器。
生成器将返回与toArray()
方法相同的值,但一个接一个地产生。完整生成后,generate()方法将再次根据缓存产生相同的值。
$m = new Datacombinator\Matrix(); $m->addSet('x', [1, [2], 3]); $m->addConstant('y', 4); foreach($m->generate() as $array) { print_r($array); }
addSet
此操作将值列表添加到矩阵中。每个值将被重复一次。提供数组数组的数组,以合并这些数组。
$m = new Datacombinator\Matrix(); $m->addSet('x', [1, [2], 3]); $m->addConstant('y', 4); ( [x] => 1 [y] => 4 ) Array ( [x] => Array ( 2 ) [y] => 4 ) Array ( [x] => 3 [y] => 4 )
addLambda
此方法将闭包、回调函数或箭头函数作为值添加。闭包将针对每个项目调用以生成新值。
闭包可以是常量或动态的。第一个仅在计算一次后总是相同的(例如,今天的日期)。第二个每次计算,并可能产生不同的值(例如,rand()值或依赖于先前生成值的闭包)。
闭包接收一个包含所有先前创建值的(数组)参数。这样,它可以基于先前生成的值创建新值。该数组按添加到矩阵的顺序填充:特别是,这意味着并非所有值都始终可用,因为其中一些值可能仍在等待。此外,作为“别名”添加的值将在最后处理,且不可用。
提供的参数是一个数组。其值的类型与添加到矩阵中的值的类型相同。对于子矩阵,它可能是一个数组或对象,具体取决于配置。
当使用闭包或箭头函数时,可以通过$this->uniqueId
属性访问唯一标识符。uniqueId是一个从1开始的int,每次使用时递增。
$m = new Datacombinator\Matrix(); // No argument for this closure, as we don't need it $m->addLambda('x', function () { return rand(0, 10);}); // This closure takes the previously created values as input // the range of random values is now twice as large $m->addLambda('y', function ($value) { return rand(0, 2 * $value['x']);}); // the closure are called each time once, so this matrix as one element, with 2 closure calls ( [x] => 4 [y] => 7 ) $m = new Matrix(); // No argument for this closure, as we don't need it $m->addLambda('x', function () { return $this->uniqueId;}); $m->addSet('y', [5,6]); ( [x] => 1 [y] => 5 ) ( [x] => 2 [y] => 6 )
$m = new Datacombinator\Matrix(); // No argument for this closure, as we don't need it $a = $m->addConstant('a', 'A'); $m->addAlias('b', $a); $m->addLambda('x', function ($r) { return $r['a'].($r['b'] ?? 'No B').($r['c'] ?? 'No C')}); $m->addConstant('c', 'C'); print_r($m->toArray()); Array ( [0] => Array ( [a] => A // No B, because it is an alias // No C, because it is defined later. It may be moved before 'x' to get access to it [x] => ANo BNo C [c] => C [b] => A ) )
addPermute
使用列表作为单个参数,并生成其中所有值的所有可能排列。
$m = new Datacombinator\Matrix(); // Create all permutation in the list : total 6 of them $m->addPermute('x', [1, 2, 3]); ( [x] => Array ( [0] => 1 [1] => 2 [2] => 3 ) ) Array ( [x] => Array ( [0] => 1 [1] => 3 [2] => 2 ) ) Array ( [x] => Array ( [0] => 2 [1] => 1 [2] => 3 ) ) Array ( [x] => Array ( [0] => 2 [1] => 3 [2] => 1 ) ) Array ( [x] => Array ( [0] => 3 [1] => 1 [2] => 2 ) ) Array ( [x] => Array ( [0] => 3 [1] => 2 [2] => 1 ) )
addCombine
使用列表作为单个集合,并生成它们的所有可能组合,从空数组(无)到所有元素。
$m = new Datacombinator\Matrix(); // Create all combinaisons from the list : total 8 of them $m->addCombine('x', [1, 2, 3]); ( [x] => Array ( ) ) Array ( [x] => Array ( [0] => 1 ) ) Array ( [x] => Array ( [0] => 2 ) ) Array ( [x] => Array ( [0] => 1 [1] => 2 ) ) Array ( [x] => Array ( [0] => 3 ) ) Array ( [x] => Array ( [0] => 1 [1] => 3 ) ) Array ( [x] => Array ( [0] => 2 [1] => 3 ) ) Array ( [x] => Array ( [0] => 1 [1] => 2 [2] => 3 ) )
addCopy
与addConstant()创建常量的值副本不同,addCopy每次都克隆输入对象。它们在生成时看起来相同,但实际上是不同的对象。
$m = new Datacombinator\Matrix(); // Create all combinaisons from the list : total 8 of them $m->addClone('x', new \stdClass); $m->addSet('i', [1, 2]); $generated = $m->toArray();
addMatrix
将矩阵添加到另一个矩阵是嵌套矩阵的方式。它还允许通过组合过程创建对象。
$m = new Datacombinator\Matrix(); $m->addSet('i', [2, 3]); $m->setClass(stdClass::class); $n = new Datacombinator\Matrix(); $n->addSet('j', [5,7]); $n->addMatrix('x', $m); Array ( [j] => 5 [x] => stdClass Object ( [i] => 2 ) ) Array ( [j] => 5 [x] => stdClass Object ( [i] => 3 ) ) Array ( [j] => 7 [x] => stdClass Object ( [i] => 2 ) ) Array ( [j] => 7 [x] => stdClass Object ( [i] => 3 ) )
矩阵有两个选项
- 缓存,在生成值后将其缓存。
- Matrix::WITHOUT_CACHE每次都重新生成矩阵,
- Matrix::WITH_CACHE生成缓存一次,并在以后重用。
- 写入模式,它配置了多重定义的情况下的行为
- Matrix::OVERWRITE是默认值。值被新的定义替换。
- Matrix::SKIP跳过任何先前定义的值
- Matrix::WARN在重用先前定义的名称时抛出异常。
addAlias
在生成的数据中的另一个槽位重复使用先前生成的值。这在需要将相同值设置在两个(或更多)槽位时非常有用。
$m = new Matrix(); $i = $m->addSet('i', [2, 3]); $m->addAlias('j', $i); print_r($m->toArray()); Array ( [0] => Array ( [i] => 2 [j] => 2 ) [1] => Array ( [i] => 3 [j] => 3 ) )
别名可以以任何顺序添加:可以从顶层矩阵或反过来从子矩阵中调用在子矩阵中创建的别名。
别名作为矩阵中的最后元素处理。它们可能在Lambda调用中不可用,Lambda调用总是先发生。
addSequence
生成从最小值到最大值的顺序数据,可选地由闭包更新。
$m = new Matrix(); $i = $m->addSequence('i', 0, 10); print_r($m->toArray()); Array ( [0] => Array ( [i] => 0 ) [1] => Array ( [i] => 1 ) [2] => Array ( [i] => 2 ) // .... [9] => Array ( [i] => 9 ) )
setClass
默认情况下,矩阵生成数组类型的值。这是最灵活的格式。
可以将这些数组转换为对象,通过提供一个类,或使用Matrix::TYPE_LIST常量将其转换为列表(自动索引的数组)。可以使用Matrix::TYPE_ARRAY常量强制使用默认类型。
对象通过不带参数的实例化创建。然后,通过公共访问设置公共属性。省略私有和受保护的属性;未设置值保持不变;也省略额外的值。
class Point { int $x, $y; } $m = new Datacombinator\Matrix(); $m->setClass(Point::class); $m->addSet('x', [1,2]); $m->addSet('y', [4,5]); Point Object ( [x] => 1 [y] => 4 )
您也可以通过使用其完全限定名称来获取一个stdClass对象。然后,所有传递的值都将转换为属性。
class Point { int $x, $y; } $m = new Datacombinator\Matrix(); $m->setClass(\stdClass::class); $m->addConstant('x', 1); $m->addConstant('y', 2); stdClass Object ( [x] => 1 [y] => 2 )
count
计算要生成的元素数量。
$m = new Datacombinator\Matrix(); $m->addSet('x', [1,2]); $m->addSet('y', [4,5]); print $m->count()." elements"; // 4 elements
toArray
以数组形式返回所有可能的组合
$m = new Datacombinator\Matrix(); $m->addSet('x', [1,2]); $m->addSet('y', [4,5]); print_r($m->toArray()); Array ( [0] => Array ( [x] => 1 [y] => 4 ) [1] => Array ( [x] => 1 [y] => 5 ) [2] => Array ( [x] => 2 [y] => 4 ) [3] => Array ( [x] => 2 [y] => 5 ) )
常见问题解答(FAQ)
如何打乱结果顺序?
使用toArray()方法,并对其应用PHP原生的shuffle()函数。
如何限制结果数量?
使用foreach()与generate()方法结合,计算所需元素的个数。然后在所有所需结果生成后停止。