eftec / arrayone
这是一个处理PHP数组的最简库。
Requires (Dev)
- phpunit/phpunit: ^8.5.36
README
这是一个无依赖的PHP数组处理库。
该库专注于处理业务数据(读取/保存文件、数据库记录、API等),因此与Numpy、Pandas、NumPHP等不同,因为它们针对不同的目标。它与Microsoft PowerQuery和Linq更为相似。它做什么?过滤、排序、重命名列、分组、验证等众多其他操作。
- 它与PHP数组一起工作。PHP数组允许使用索引和/或关联值使用层次结构。
- 它旨在提高速度。
- 它是简约的,使用最少的依赖项和仅1个PHP类。你讨厌一个简单的库添加整个框架作为依赖项吗?在这里不会这样。
- 它使用流畅/嵌套表示法工作。
- 每个方法都使用PhpDoc进行文档化。
- ArrayOne
基本示例
// Reducing an array using aggregate functions: $invoice=[ 'id'=>1, 'date'=>new DateTime('now'), 'customer'=>10, 'detail'=>[ ['idproduct'=>1,'unitPrice'=>200,'quantity'=>3], ['idproduct'=>2,'unitPrice'=>300,'quantity'=>4], ['idproduct'=>3,'unitPrice'=>300,'quantity'=>5], ] ]; $arr=ArrayOne::set($invoice['detail']) ->reduce(['unitPrice'=>'sum','quantity'=>'sum']) ->all(); //['unitPrice'=>800,'quanty'=>12] // or also $arr=(new ArrayOne($invoice['detail'])) ->reduce(['unitPrice'=>'sum','quantity'=>'sum']) ->all(); //['unitPrice'=>800,'quanty'=>12]
入门
首先,您必须安装库。您可以下载此库或使用Composer进行安装
composer require eftec/arrayone
一旦安装了库并将其包含在内,您就可以使用它了
use eftec\ArrayOne; ArrayOne::set($array); // Initial operator: $array is our initial array. ->someoperator1() // Middle operator: here we do one or many operations to transform the array ->someoperator2() ->someoperator3() ->all(); // End operator: and we get the end result that usually is an array but it could be even a literal.
概念
$array=['hello' // indexed field 'field2'=>'world', // named field 'fields'=>[ // a field with sub-fields 'alpha'=>1, 'beta'=>2 ], 'table'=>[ // a field with a list of values (a table) ['id'=>1,'name'=>'red'], ['id'=>2,'name'=>'orange'], ['id'=>3,'name'=>'blue'], ] ];
- 索引和命名字段的工作方式类似。
- 有时,一些字段包含一个值数组,该数组的行为类似于表(请参阅table字段)
初始运算符
初始运算符是链中的第一个运算符。
集合
它设置要转换的数组,并开始管道。除非您使用构造函数,否则它必须是第一个运算符。
ArrayOne::set($array)->all(); ArrayOne::set($array,$object)->all(); // the object is used by validation() ArrayOne::set($array,SomeClass:class)->all(); // the object is used by validation()
- 参数 array|null $array
- 参数 object|null|string $service 服务实例。您可以使用类或对象。
setRequest
它设置初始数组,从请求中读取值(get/post/header等)
示例
ArrayOne::setRequest([ 'id'=>'get', // $_GET['id'] if not found then it uses the default value (null) 'name'=>'post|default', // $_POST['name'], if not found then it uses "default" 'content'=>'body' // it reads from the POST body ],null); // null is the default value if not other default value is set.
- 参数 array $fields 当值要读取时,'id'=>'type;defaultvalue'的关联数组。类型
get:从查询字符串中获取
post:从POST中获取
header:从标题中获取
request:如果从POST中获取,否则从GET中获取
cookie:从cookie中获取
body:从POST体中获取(值未序列化)
verb:从请求方法(GET/POST/PUT等)中获取 - 参数 mixed $defaultValue 如果找不到值且未设置其他默认值时,所有默认值。
- 参数 ?string $separator 默认值:'.',当字段嵌套时使用的分隔符字符。
使用'.'作为分隔符的示例 html
获得的结果:$result['a']['b']='hello'; - 返回值 ArrayOne
setJson
它使用JSON设置数组。 示例:
ArrayOne::setJson('{"a":3,"b":[1,2,3]}')->all();
- 参数 string $json 要解析的值。
setCsv
它使用CSV设置数组。此CSV必须包含表头。
示例
ArrayOne::setCsv("a,b,c\n1,2,3\n4,5,6")->all();
- 参数 字符串 $string 要解析的字符串
- 参数 字符串 $separator 默认为","。设置字段分隔符(只能是一个字符)。
- 参数 字符串 $enclosure 默认为"\"。设置字段封装字符(只能是一个字符)。
- 参数 字符串 $escape 默认为"\"。设置转义字符(只能是一个字符)。
setCsvHeadless
它使用无头CSV设置数组。
示例
ArrayOne::setCsvHeadLess("1,2,3\n4,5,6")->all(); ArrayOne::setCsvHeadLess("1,2,3\n4,5,6",['c1','c2','c3'])->all();
- 参数 字符串 $string 要解析的字符串
- 参数 数组|null $header 如果表头为null,则创建一个索引数组。
如果表头是数组,则用作表头 - 参数 字符串 $separator 默认为","。设置字段分隔符(只能是一个字符)。
- 参数 字符串 $enclosure 默认为"\"。设置字段封装字符(只能是一个字符)。
- 参数 字符串 $escape 默认为"\"。设置转义字符(只能是一个字符)。
中间运算符
中间运算符是介于初始运算符 set() 和结束运算符 all() 或 getCurrent() 之间的运算符。它们执行转换,并且可以堆叠。
example
ArrayOne::set($array) ->group('col1',['col2'=>'sum']) // middle operator #2 ->all();
列
返回一个包含值的数组。
示例
$this->col('c1'); // [['c1'=>1,'c2'=>2],['c1'=>3,'c2'=>4]] => [['c1'=>1],['c1'=>3]];
columnToIndex
它将列转换为索引
示例
$this->indexToField('colold'); // [['colold'=>'a','col1'=>'b','col2'=>'c'] => ['a'=>['col1'=>'b','col2'=>'c']]
- 参数 混合 $oldColumn 旧列。此列将被转换为索引
filter
它过滤值。如果条件为假,则删除行。它使用 array_filter()
索引不会被重建。 示例:
$array = [['id' => 1, 'name' => 'chile'], ['id' => 2, 'name' => 'argentina'], ['id' => 3, 'name' => 'peru']]; // get the row #2 "argentina": // using a function: $r = ArrayOne::set($array)->filter(function($row, $id) {return $row['id'] === 2;}, true)->result(); // using a function a returning a flat result: $r = ArrayOne::set($array)->filter(function($row, $id) {return $row['id'] === 2;}, false)->result(); // using an associative array: $r = ArrayOne::set($array)->filter(['id'=>'eq;2'], false)->result(); // using an associative array that contains an array: $r = ArrayOne::set($array)->filter(['id'=>['eq,2]], false)->result(); // multiples conditions: id=2 and col=10 $r = ArrayOne::set($array)->filter([['id'=>'eq;2'],['col','eq;10]], false)->result();
您可以在 examplefindandfilter 中找到一个示例。注意:有关条件的更多信息,请参阅 validate。
find
它返回一个数组,包含与条件匹配的元素的键和值。
- 参数 可调用|数组 $condition 您可以使用可调用的函数 ($row,$id):bool {}
或比较数组 ['id'=>'eq;2|lt;3'] "|" 添加更多比较
或比较数组 [['id=>['eq',2]]],['id'=>['lt',3]] - 参数 布尔 $onlyFirst 如果为true,则仅返回第一个值
- 参数 字符串 $mode =['all','key','value'] // (默认为 all)
all 返回获取到的键和值
key 仅返回键
value 仅返回值
示例
ArrayOne::set($array)->find(function($row, $id) { return $row['id'] === 2; })->all(); // [[0,"apple"],[3,"pear"]]
它使用与 filter() 相同的条件
isIndexArray() isIndex()
如果数组是索引数组,则返回true。它不会扫描整个数组,而是仅在索引0存在并且是第一个值时返回true。
示例
ArrayOne::isIndexArray(['cocacola','fanta']); // true ArrayOne::isIndexArray(['prod1'=>'cocacola','prod2'=>'fanta']); // false (associative array) ArrayOne::isIndexArray('cocacola'); // false (not array) ArrayOne::set(['cocacola','fanta'])->isIndex(); // dynamic method (true)
isIndexTableArray() isIndexTable()
它返回值为索引数组的值,其中第一个值是一个数组(即表格)示例:
ArrayOne::isIndexTableArray([['cocacola','fanta']]); // true ArrayOne::isIndexTableArray(['cocacola','fanta']); // false ArrayOne::isIndexTableArray(['first'=>['hello'],'second'=>'world']) // false
first
它返回数组的第一个元素。
- 返回值 $this
flat
它展平结果。如果结果是包含单行的数组,则返回不带数组的行
示例
$this->flat(); // [['a'=>1,'b'=>2]] => ['a'=>1,'b'=>2]
- 返回值 $this
group
它对一列进行分组并返回分组后的列及其值聚合。
分组值用作新的索引键。
示例
// group in the same column using a predefined function: $this->group('type',['c1'=>'sum','price'=>'sum']); // ['type1'=>['c1'=>20,'price'=>30]] // group in a different column using a predefined function: $this->group('type',['newcol'=>'sum(amount)','price'=>'sum(price)']); // group using an indexed index: $this->group('type',['c1'=>'sum','pri'=>'sum','grp'=>'group'],false); // [['c1'=>20,'pri'=>30,'grp'=>'type1']] // group using a function: $this->group('type',['c1'=>function($cumulate,$row) { return $cumulate+$row['c1'];}]); // group using two functions, one per every row and the other at the end: $this->group('type',['c1'=>[ function($cumulate,$row) { return $cumulate+$row['c1'];}, function($cumulate,$numrows) { return $cumulate/$numRows;}]); // obtain the average of c1
- 参数 混合 $column 要分组的列。
- 参数 数组 $functionAggregation 关联数组 ['col-to-agregate'=>'aggregation']
或 ['new-col'=>'aggregation(col-to-agregate)']
或 ['col-to-aggr'=>function($cumulate,$row) {}]
或 ['col-to-aggr'=>[function($cumulate,$row){},function($cumulate,$numRows){}]]
stack:按列堆叠行(类似于交叉表)。
count:计数
avg:平均值
min:最小值
max:最大值
sum:总和
first:第一个
last:最后一个
group:分组值 - 参数 布尔 $useGroupAsIndex (默认为 true),如果为 true,则结果将使用分组值作为索引
如果为 false,则结果将返回值作为索引数组。
example
$array=[ ['cat'=>'cat1','col_min'=>1,'col_max'=>1,'col_sum'=>1,'col_avg'=>1,'col_first'=>'john1','col_last'=>'doe1'], ['cat'=>'cat2','col_min'=>2,'col_max'=>2,'col_sum'=>2,'col_avg'=>2,'col_first'=>'john2','col_last'=>'doe2'], ['cat'=>'cat3','col_min'=>3,'col_max'=>3,'col_sum'=>3,'col_avg'=>3,'col_first'=>'john3','col_last'=>'doe3'], ['cat'=>'cat1','col_min'=>4,'col_max'=>4,'col_sum'=>4,'col_avg'=>4,'col_first'=>'john4','col_last'=>'doe4'], ['cat'=>'cat2','col_min'=>5,'col_max'=>5,'col_sum'=>5,'col_avg'=>5,'col_first'=>'john5','col_last'=>'doe5'] ]; $result=ArrayOne::set($array) ->group('cat',[ 'col_min'=>'min', 'col_max'=>'max', 'col_sum'=>'sum', 'col_avg'=>'avg', 'col_count'=>'count', 'col_first'=>'first', 'col_last'=>'last', ]) ->all(); /* [ 'cat1' => ['col_min' => 1, 'col_max' => 4, 'col_sum' => 5, 'col_avg' => 2.5, 'col_first' => 'john1', 'col_last' => 'doe4', 'col_count' => 2,], 'cat2' => ['col_min' => 2, 'col_max' => 5, 'col_sum' => 7, 'col_avg' => 3.5, 'col_first' => 'john2', 'col_last' => 'doe5', 'col_count' => 2,], 'cat3' => ['col_min' => 3, 'col_max' => 3, 'col_sum' => 3, 'col_avg' => 3, 'col_first' => 'john3', 'col_last' => 'doe3', 'col_count' => 1,], ];
indexToCol
它将索引转换为字段,并重新编号数组
示例
$this->indexToCol('colnew'); // ['a'=>['col1'=>'b','col2'=>'c']] => [['colnew'=>'a','col1'=>'b','col2'=>'c']
- 参数 混合 $newColumn 新列的名称
- 返回值 $this
join
将当前数组与另一个数组连接
如果两个数组的列名相同,则保留当前名称。
示例
$products=[['id'=>1,'name'=>'cocacola','idtype'=>123]]; $types=[['id'=>123,'desc'=>'it is the type #123']]; ArrayOne::set($products)->join($types,'idtype','id')->all() // [['id'=>1,'prod'=>'cocacola','idtype'=>123,'desc'=>'it is the type #123']] "id" is from product.
- 参数 数组|null $arrayToJoin
- 参数 mixed $column1 当前数组的列
- 参数 mixed $column2 要连接的数组的列
- 返回值 $this
last
返回数组的最后一个元素。
- 返回值 $this
map
为数组中的每个元素调用一个函数。 示例:
$this->map(function($row) { return strtoupper($row); });
- 参数 callable|null $condition 要调用的函数。
- 返回值 $this
mask
使用另一个数组对当前数组进行遮罩。
遮罩会删除不属于我们的遮罩的字段
遮罩智能识别表格,因此只需指定第一行即可遮罩多个值。
示例
$array=['a'=>1,'b'=>2,'c'=>3,'items'=>[[a1'=>1,'a2'=>2,'a3'=3],[a1'=>1,'a2'=>2,'a3'=3]]; $mask=['a'=>1,'items'=>[[a1'=>1]]; // [[a1'=>1]] masks an entire table $this->mask($mask); // $array=['a'=>1,'items'=>[[a1'=>1],[a1'=>1]];
- 参数 array $arrayMask 包含遮罩的关联数组。遮罩可以包含任何值。
- 返回值 ArrayOne
npos
返回数组的第n个位置。
- 参数 $index
- 返回值 $this
reduce
您可以使用聚合或自定义函数来压缩(扁平化)数组。 示例:
$this->reduce(['col1'=>'sum','col2'=>'avg','col3'=>'min','col4'=>'max']); $this->reduce(function($row,$index,$prev) { return ['col1'=>$row['col1']+$prev['col1]]; });
- 参数 array|callable $functionAggregation 一个关联数组,其中索引是列,值是聚合函数
使用语法:function ($row,$index,$prev) 的函数,其中 $prev 是累加器值 - 返回值 $this
removecol
删除列
示例
$this->removeCol('col1'); $this->removeCol(['col1','col2']);
- 参数 mixed $colName 列名或列(数组)
- 返回值 $this
removerow
删除具有id $rowId 的行。如果行不存在,则不执行任何操作 示例:
$this->removeRow(20);
- 参数 mixed $rowId 要删除的行的id
- 参数 bool $renumber 如果为true,则重新编号列表
示例:如果删除1,则 $renumber=true: [0=>0,1=>1,2=>2] => [0=>0,1=>2]
示例:如果删除1,则 $renumber=false: [0=>0,1=>1,2=>2] => [0=>0,2=>2] - 返回值 $this
removeFirstRow
删除第一行或多行。数值索引可以重新编号。 示例:
$this->removeFirstRow(); // remove the first row $this->removeFirstRow(3); // remove the first 3 rows
- 参数 int $numberOfRows 要删除的行数,默认为1(第一行)
- 参数 bool $renumber 如果为true,则重新编号列表
示例:如果删除1,则 $renumber=true: [0=>0,1=>1,'x'=>2] => [0=>0,1=>2]
示例:如果删除1,则 $renumber=false: [0=>0,1=>1,2=>2] => [0=>0,2=>2] - 返回值 $this
removeLastRow
删除最后一行或多行 示例:
$this->removeLastRow(); // remove the last row $this->removeLastRow(3); // remove the last 3 rows
- 参数 int $numberOfRows 要删除的行数
- 参数 bool $renumber 如果为true,则重新编号列表(由于我们正在删除最后一个值,因此通常不需要它
示例:如果删除1,则 $renumber=true: [0=>0,1=>1,2=>2] => [0=>0,1=>2]
示例:如果删除1,则 $renumber=false: [0=>0,1=>1,2=>2] => [0=>0,2=>2] - 返回值 $this
removeDuplicate
此函数删除表格的重复项。
示例
$this->removeDuplicate('col');
- 参数 mixed $colName 比较行是否重复的列
- 返回值 $this
modCol
添加或修改列。 示例:
$this->modCol('col1',function($row,$index) { return $row['col2']*$row['col3']; });
- 参数 string|int|null $colName 列名。如果为null,则使用整个行
- 参数 callable|null $operation 实现操作的函数
- 返回值 $this
sort
排序数组
示例
$this->sort('payment','desc'); // sort an array using the column paypent descending. $this->sort(['col1','col2'],'desc'); $this->sort(['col1','col2'],['desc','asc']);
- 参数 mixed $column 如果列是null,则对行进行排序(而不是对行的列进行排序)
- 参数 string $direction =['asc','desc'][$i] 递增或递减。
- 返回值 $this
createValidateExample
使用示例创建验证数组
validate
使用比较表验证当前数组
示例
$valid=$this->set($array)->validate([ 'id'=>'int', 'price'=>'int|between;1,20' // the price must be an integer and it must be between 1 and 20 (including them). 'table'=>[['col1'=>'int';'col2'=>'string|notnull,,the value is required|']], // note the double [[ ]] to indicate a table of values 'list'=>[['int']] ]); $valid->all(); // it gets an associative array with all the errors (or null if not error) $valid->flat()->all(); // if you want a flat result. $valid->errorStack; // it gets an associative array with only the errors. If nested array, then some values could be overriden. $valid->isValid(); // returns true if the validation passes, otherwise, it returns false.
使用自定义函数的示例
// 1) defining the service class. class ServiceClass { /** * @param mixed $value the value to evaluate * @param mixed $compare the value to compare (optional) * @param ?string $msg the message to return if fails * @return bool */ public function test($value,$compare=null,&$msg=null): bool { return true; } } // 2.1) and setting the service class using the class ValidateOne ->set($array,ServiceClass:class) ->validate('field'=>'fn:test') // or ->validate('field'=>[['fn','test']]) ->all(); // 2.2) or you could use an instance $obj=new ServiceClass(); ValidateOne ->set($array,$obj) ->validate('field'=>'fn:test') // or ->validate('field'=>[['fn','test']]) ->all();
- 参数 array $comparisonTable 比较表,是一个关联表,包含使用以下语法进行比较的条件:[index=>"condition|condition2..."]。
- 条件可以表达为: <condition name>;<value>;<custom error message>
- 如果 <condition> 以 "not" 开头,则它被否定,例如:"notalpha"
- <value> 可以是一个简单的字面量(1,hello等)或值的列表(用逗号分隔)
- <custom error message> 可以包含以下变量: %field 字段的id,%value 字段的当前值,%comp 要比较的值,%first 要比较的第一个值,%second 要比较的第二个值,例如 "%field (%value) 不等于 %comp",%rowid 是当前行的id(如果有)
- 条件可以表达为: <condition name>;<value>;<custom error message>
- 参数 bool $extraFieldError 如果为真且当前数组值多于比较表,则返回错误。
末尾运算符
getAll()
返回整个数组的转换结果。
示例
$this->set($array)->getAll();
isValid()
如果没有错误,则返回true。
示例
if ($this->set($array)->valid($arrayComparison)->isValid()) { // do something. }
注意:您也可以获取验证结果:->valid($arrayc)->all();
注意2:如果您想要一个包含错误的简单数组,可以使用 $this::errorStack;
示例
$this->set($array)->all();
- 返回值 mixed
其他方法
不属于其他类别的方法。这些方法不可堆叠。
makeValidateArrayByExample
使用示例数组生成 validate-array。它可以用于 validation() 和 filter()。
示例
$this->makeValidateArrayByExample(['1','a','f'=>3.3]); // ['int','string','f'=>'float'];
- 参数 array $array
- 返回值 array
makeRequestArrayByExample
它创建一个关联数组,可用于 setRequest()。
示例
$this->makeRequestArrayByExample(['a'=1,'b'=>2]); // ['a'='post','b'=>'post'];
- 参数 array $array 包含一些值的关联数组。
- 参数 string $type=['get','post','request','header','cookie'][$i] 默认类型
- 返回值 array
版本
- 2.5. 2024-09-20
- [新] keepCol()
- [新] coolRename()
- [新] shuffle()
- 2.4 2024-08-15
- [更新] sort() 现在允许按多列分组
- [修复] group() 修复了返回值。如果使用多列,则新分组列可以分割。
- [新] splitColumn() 将列分割成两个或更多列。~~
- 2.3 2024-08-10
- [新] sum(),min(),max(),avg(),count(),aggr()
- 2.2 2024-08-06
- sort() 现在接受多列。
- 2.1 2024-08-03
- removeDuplicate(),group() 现在接受多列。
- 2.00 2024-03-10
- nav() 和 currentArray() 从 2.0 版本中移除。库被优化和精简,这些函数是冗余的。
迁移
- nav() 和 currentArray() 从 2.0 版本中移除。库被优化和精简,这些函数是冗余的。
// before: $r=ArrayOne::set($array)->nav('field')->...->all(); // now: $r=ArrayOne::set($array['field'])->...->all(); // before: $r=ArrayOne::set($array)->nav('field')->...->currentArray(); // now: $r=$array; $r['field']=ArrayOne::set($array['field'])->...->all();
- 1.12 2024-03-01
- 更新依赖项到 PHP 7.4。PHP 7.2 的扩展支持已于 3 年前结束。
- 1.11 2024-03-01
- 添加了方法 find()
- 添加了方法 isIndexArray() 和 isIndexTableArray()
- 现在 find() 和 filter() 允许多个条件
- 并且 find() 和 filter(),条件 ['field'='eq;2'] 可以写成 ['field','2']
- 1.10 2024-02-24
- 为 validate() 添加了更多文档
- 现在 validate 也返回数组 $this::$errorStack
- 新方法 isValid() 如果验证没有错误,则返回 true。否则返回 false。
- 1.9 2023-11-13
- 添加了 rowToValue()
- 1.8.3 2023-09-16
- offsetGet() 在 php 8.1 中生成警告(已修复)
- current() 已标记为已弃用(但仍然可用),请使用 getCurrent()
- 1.8.2 2023-09-16
- 解决了 composer.json 中的 psr-4 问题
- 1.8.1 2023-09-16
- 更改了 PHPDOC 注释,现在它使用 markdown 而不是 "pre" 标签。
- 添加了 ArrayAccess 接口。
- 1.8 2023-07-29
- [修改] group() 允许指定自定义函数(s)。
- 1.7 2023-06-04
- [新] group() 允许返回分组值。它还允许以索引数组的形式返回值。
- 1.6 2023-04-10
- [优化] setCurrentArray() 现仅在调用 nav() 或返回值时使用。
- 1.5 2023-04-07
- [新] filtercondition() 现在允许条件作为数组。
- 1.4 2023-04-05
- [修复] filtercondition() 修复了值为 null 时的警告。
- [新] group() 现在允许堆叠元素
- [新] group() 现在允许指定新列
- 1.3 2023-03-31
- 验证现在允许否定("not" 前缀)。
- 1.2
- 将方法 getValidateArrayByExample() 重命名为 makeValidateArrayByExample()
- 新方法 makeRequestArrayByExample()
- 新方法 setRequest()
- 将方法 setCol() 重命名为 modCol()。以 "set" 开头的方法用于初始化变量。
- 1.1 2023-03-28
- 方法 filter() 现在接受比较数组和可调用的函数。
- 新方法 getValidateArrayByExample()
- 新方法 removeRow()
- 新方法 removeFirstRow()
- 新方法 removeLastRow()
- 新方法 setCsv()
- 新方法 setJson()
- 1.0 2023-03-26 首个版本
许可证
版权 Jorge Castro Castillo 2023-2024。许可协议:LGPL-3.0 和商业许可。
简要说明
- 我可以在闭源应用程序中免费使用吗?如果不对此库进行修改,则可以。
- 如果您修改它,则必须共享源代码。
- 如果您想私下修改,则必须购买许可证。