martinvenus/knapsack

PHP的集合库

10.0.1 2021-11-24 11:36 UTC

README

PHP的集合管道库

SensioLabsInsight Build Status Code Coverage Scrutinizer Code Quality

Knapsack 是一个针对 PHP >= 5.6 的集合库,实现了 Clojures sequences 提出的大多数序列操作,并增加了一些额外的操作。所有功能都作为函数(用于函数式编程)和作为 集合管道 对象方法提供。

Knapsack 的核心是其 Collection 类。然而,它的每个方法都调用一个同名的简单函数来执行实际的重活。这些函数位于 DusanKasan\Knapsack 命名空间中,您可以在 这里 找到它们。Collection 是一个 Traversable 实现(通过 IteratorAggregate),它接受 Traversable 对象、数组或作为构造函数参数的可调用对象,该对象生成 Traversable 对象或数组。它提供了 Clojures sequence 的大多数功能以及一些额外功能。它也是不可变的 - 对集合执行的操作将返回新的集合(或值),而不是修改原始集合。

Collection 的大多数方法返回惰性集合(如 filter/map 等)。然而,一些返回非惰性集合(reverse)或简单值(count)。对于这些操作,集合中的所有项目都必须迭代(并实现)。还有一些操作(drop)会迭代集合中的某些项目,但不会在结果中影响/返回它们。每个操作的行为以及惰性都是注明的。

如果您想查看这里没有提供的更多示例用法,请查看 规格 和/或 场景。还有您可以在自己的机器上运行的 性能测试,以查看此库的计算时间影响(以下列出了这些输出)。

您可以自由地报告您发现的任何 问题。我将尽我所能尽快修复它们,但欢迎社区 pull requests 修复它们。

文档

请在 http://dusankasan.github.io/Knapsack 查看文档(这是本说明的格式化版本)。

安装

使用 Composer 需要此包。

composer require dusank/knapsack

用法

通过静态或动态构造函数实例化

use DusanKasan\Knapsack\Collection;

$collection1 = new Collection([1, 2, 3]);
$collection2 = Collection::from([1, 2, 3]); //preferred since you can call methods on its result directly.

处理数组、可遍历对象或生成可遍历对象的可调用对象

$collection1 = Collection::from([1, 2, 3]);
$collection2 = Collection::from(new ArrayIterator([1, 2, 3]);

//Used because Generator can not be rewound
$collection2 = Collection::from(function() { //must have 0 arguments
    foreach ([1, 2, 3] as $value) {
        yield $value;
    }
});

基本的 map/reduce

$result = Collection::from([1, 2])
    ->map(function($v) {return $v*2;})
    ->reduce(function($tmp, $v) {return $tmp+$v;}, 0);
    
echo $result; //6

使用 Knapsack 的集合函数执行相同的 map/reduce

$result = reduce(
    map(
        [1, 2], 
        function($v) {return $v*2;}
    ),
    function($tmp, $v) {return $tmp+$v;},
    0
);

echo $result; //6

获取斐波那契数列的前 5 项

$result = Collection::iterate([1,1], function($v) {
        return [$v[1], $v[0] + $v[1]]; //[1, 2], [2, 3] ...
    })
    ->map('\DusanKasan\Knapsack\first') //one of the collection functions
    ->take(5);
    
foreach ($result as $item) {
    echo $item . PHP_EOL;
}

//1
//1
//2
//3
//5

如果从返回集合中一个项目的函数返回数组或可遍历对象,则可以使用可选标志将其转换为 Collection。默认情况下,它返回项目本身。

$result = Collection::from([[[1]]])
    ->first(true)
    ->first();
    
var_dump($result); //[1]

集合是不可变的

function multiplyBy2($v)
{
    return $v * 2;
}

function multiplyBy3($v)
{
    return $v * 3;
}

function add($a, $b)
{
    return $a + $b;
}

$collection = Collection::from([1, 2]);

$result = $collection
    ->map('multiplyBy2')
    ->reduce(0, 'add');
    
echo $result; //6

//On the same collection
$differentResult = $collection
    ->map('multiplyBy3')
    ->reduce(0, 'add');
    
echo $differentResult; //9

键不是设计为唯一的

这会影响性能。只有在您需要调用 toArray() 时才成问题,此时您应该先调用 values()。

$result = Collection::from([1, 2])->concat([3,4]);
    
//arrays have unique keys
$result->toArray(); //[3,4]
$result->values()->toArray(); //[1, 2, 3, 4]

//When iterating, you can have multiple keys.
foreach ($result as $key => $item) {
    echo $key . ':' . $item . PHP_EOL;
}

//0:1
//1:2
//0:3
//1:4

提供了 Collection 特性

如果您希望直接在现有类中使用所有集合方法,无需代理它们的调用,您只需使用提供的CollectionTrait。默认情况下,这将适用于任何可遍历对象。在其他任何类中,您都需要重写由特性提供的getItems()方法。请注意,在调用filter或其他返回集合的方法之后,返回的实际类型将是Collection,而不是原始的可遍历对象。

class AwesomeIterator extends ArrayIterator {
    use CollectionTrait;
}

$iterator = new AwesomeIterator([1, 2, 3]);
$iterator->size(); //3

性能测试

PHP 5.6

+------------------------------------------------------------------------------------+-----------------------+---------------------------+----------------------+
| operation details                                                                  | native execution time | collection execution time | difference (percent) |
+------------------------------------------------------------------------------------+-----------------------+---------------------------+----------------------+
| array_map vs Collection::map on 10000 integers (addition)                          | 0.0034945011138916s   | 0.0034625053405762s       | 99%                  |
| array_map vs Collection::map on 10000 strings (concatenation)                      | 0.004361891746521s    | 0.0049739360809326s       | 114%                 |
| array_map vs Collection::map on 10000 objects (object to field value)              | 0.02332329750061s     | 0.027161455154419s        | 116%                 |
| array_map vs Collection::map on 10000 md5 invocations                              | 0.0086771726608276s   | 0.0080755949020386s       | 93%                  |
| array_map vs Collection::map on 10000 integers n, counting sum(0, n) the naive way | 1.5985415458679s      | 1.580038356781s           | 98%                  |
+------------------------------------------------------------------------------------+-----------------------+---------------------------+----------------------+

PHP 7.1.1

+------------------------------------------------------------------------------------+-----------------------+---------------------------+----------------------+
| operation details                                                                  | native execution time | collection execution time | difference (percent) |
+------------------------------------------------------------------------------------+-----------------------+---------------------------+----------------------+
| array_map vs Collection::map on 10000 integers (addition)                          | 0.00082111358642578s  | 0.001681661605835s        | 204%                 |
| array_map vs Collection::map on 10000 strings (concatenation)                      | 0.00081214904785156s  | 0.0015116214752197s       | 186%                 |
| array_map vs Collection::map on 10000 objects (object to field value)              | 0.0015491008758545s   | 0.0036969423294067s       | 238%                 |
| array_map vs Collection::map on 10000 md5 invocations                              | 0.0032038688659668s   | 0.0039427280426025s       | 123%                 |
| array_map vs Collection::map on 10000 integers n, counting sum(0, n) the naive way | 0.93844709396362s     | 0.93354930877686s         | 99%                  |
+------------------------------------------------------------------------------------+-----------------------+---------------------------+----------------------+

构造函数

这些都是创建Collection类的方法。有一个默认构造函数和一些命名的(静态)构造函数。

new(iterable|callable $input)

默认构造函数接受数组、可遍历对象或无参数的调用,并产生可遍历对象或数组。对于调用参数的使用案例,例如生成器,它不能重置,因此集合必须在重置自身时能够重建它。

$collection = new Collection([1, 2, 3]);
$collection = new Collection(new ArrayIterator([1, 2, 3]));
$generatorFactory = function () {
    foreach ([1, 2] as $value) {
        yield $value;
    }
};

$collection = new Collection($generatorFactory);

from(iterable|callable $input)

Collection::from是默认构造函数的静态别名。这是创建集合的首选方式。

$collection = Collection::from([1, 2, 3]);
$collection = Collection::from(new ArrayIterator([1, 2, 3]));
$generatorFactory = function () {
    foreach ([1, 2] as $value) {
        yield $value;
    }
};

$collection = Collection::from($generatorFactory);

iterate(mixed $input, callable $function)

返回一个惰性值集合,第一个值是$input,所有后续值是通过将$function应用于集合中的最后一个值来计算的。默认情况下,这将产生一个无限集合。但是,您可以通过抛出NoMoreItems异常来结束集合。

$collection = Collection::iterate(1, function ($value) {return $value + 1;}); // 1, 2, 3, 4 ...

repeat(mixed $value, int $times = -1)

返回一个惰性值集合,其中包含重复的价值$value,重复$times次。如果没有提供$times,则集合是无限的。

Collection::repeat(1); //infinite collection of ones
Collection::repeat(1, 4)->toArray(); //[1, 1, 1, 1]

range(int $start = 0, int $end = null, int step = 1)

返回一个惰性值集合,从$start开始,通过$step递增,直到达到$end。

Collection::range(0, 6, 2)->toArray(); //[0, 2, 4, 6]

操作

这些都是Collection类提供的操作(方法)。对于每一个,Knapsack命名空间中都有一个具有相同名称的函数。函数的足迹与方法相同,除了它有一个额外的参数被前置——集合(数组或可遍历对象)。

标准迭代器方法

它实现了https://php.ac.cn/manual/en/class.iterator.php

append(mixed $item, mixed $key = null) : Collection

返回一个惰性集合,其中包含此集合的项目,并将$item添加为最后一个元素。如果没有提供$key,其键将是序列中的下一个整数。

Collection::from([1, 3, 3, 2])
    ->append(1)
    ->toArray(); //[1, 3, 3, 2, 1]
Collection::from([1, 3, 3, 2])
    ->append(1, 'key')
    ->toArray(); //[1, 3, 3, 2, 'key' => 1]
toArray(append([1, 3, 3, 2], 1, 'key')); //[1, 3, 3, 2, 'key' => 1]

average() : int|float

返回此集合中值的平均值。

Collection::from([1, 2, 3, 2])->average(); //2
Collection::from([1, 2, 3, 2, 2])->average(); //2.2
Collection::from([])->average(); //0
average([1, 2, 3]); //2

combine(iterable $collection, bool $strict = false) : Collection

将此集合的值作为键,将$collection的值作为值结合在一起。结果集合的长度等于较小集合的大小。如果$strict为true,两个集合的大小必须相等,否则将抛出ItemNotFound。当strict时,集合立即实现。

Collection::from(['a', 'b'])
    ->combine([1, 2])
    ->toArray(); //['a' => 1, 'b' => 2]
toArray(combine(['a', 'b'], [1, 2])); //['a' => 1, 'b' => 2]

concat(iterable ...$collections) : Collection

返回一个惰性集合,其中包含此集合的项,然后是第一个参数中的集合的项,然后是第二个参数中的集合的项,依此类推。

Collection::from([1, 3, 3, 2])
    ->concat([4, 5]) //If we would convert to array here, we would loose 2 items because of same keys [4, 5, 3, 2]
    ->values() 
    ->toArray(); //[1, 3, 3, 2, 4, 5]
toArray(values(concat([1, 3, 3, 2], [4, 5]))); //[1, 3, 3, 2, 4, 5]  

contains(mixed $needle) : bool

如果$needle存在于集合中,则返回true。

Collection::from([1, 3, 3, 2])->contains(2); //true
contains([1, 3, 3, 2], 2); //true

countBy(callable $function) : Collection

返回一个集合,其键是$function(value, key)的返回值,值是此集合中返回此值的项的数量。

Collection::from([1, 2, 3, 4, 5])
    ->countBy(function ($value) {
        return $value % 2 == 0 ? 'even' : 'odd';
    })
    ->toArray(); //['odd' => 3, 'even' => 2]  
toArray(countBy([1, 2, 3, 4, 5], function ($value) {return $value % 2 == 0 ? 'even' : 'odd';}));      

cycle() : Collection

返回一个无限惰性集合,其中的项无限重复。

Collection::from([1, 3, 3, 2])
    ->cycle()
    ->take(8) //we take just 8 items, since this collection is infinite
    ->values()
    ->toArray(); //[1, 3, 3, 2, 1, 3, 3, 2]
toArray(values(take(cycle([1, 3, 3, 2]), 8))); //[1, 3, 3, 2, 1, 3, 3, 2]

diff(iterable ...$collections) : Collection

返回一个惰性集合,其中的项在$collection中,但在其他任何参数中都不是,以第一个集合的键为索引。注意...$collections是按非惰性方式迭代的。

Collection::from([1, 3, 3, 2])
    ->diff([1, 3])
    ->toArray(); //[3 => 2]
toArray(diff([1, 3, 3, 2], [1, 3])); //[3 => 2]

distinct() : Collection

返回一个包含不同项的懒加载集合。判断项是否在集合中的比较方式与 in_array 相同。

Collection::from([1, 3, 3, 2])
    ->distinct()
    ->toArray(); //[1, 3, 3 => 2] - each item has key of the first occurrence
toArray(distinct([1, 3, 3, 2])); //[1, 3, 3 => 2] - each item has key of the first occurrence

drop(int $numberOfItems) : Collection

一种切片形式,返回除了前 $numberOfItems 项之外的所有项。

Collection::from([1, 2, 3, 4, 5])
    ->drop(4)
    ->toArray(); //[4 => 5]
toArray(drop([1, 2, 3, 4, 5], 4)); //[4 => 5]    

dropLast($numberOfItems = 1) : Collection

返回一个懒加载集合,跳过最后 $numberOfItems 项。这些项仍然会被实现,但会被跳过。

Collection::from([1, 2, 3])
    ->dropLast()
    ->toArray(); //[1, 2]
Collection::from([1, 2, 3])
$collection
    ->dropLast(2)
    ->toArray(); //[1]
toArray(dropLast([1, 2, 3], 2)); //[1]    

dropWhile(callable $function) : Collection

通过从该集合中移除项,直到第一个使 $function(value, key) 返回 false 的项,返回一个懒加载集合。

Collection::from([1, 3, 3, 2])
    ->dropWhile(function ($v) {
        return $v < 3;
    })
    ->toArray(); //[1 => 3, 2 => 3, 3 => 2])
Collection::from([1, 3, 3, 2])
    ->dropWhile(function ($v, $k) {
        return $k < 2 && $v < 3;
    })
    ->toArray(); //[1 => 3, 2 => 3, 3 => 2])
Collection::from([1, 3, 3, 2])
    ->dropWhile(function ($v, $k) {
        return $k < 2 && $v < 3;
    })
    ->toArray(); //[1 => 3, 2 => 3, 3 => 2])
toArray(values(dropWhile([1, 3, 3, 2], function ($v) {return $v < 3;}))); // [3, 3, 2]

dump(int $maxItemsPerCollection = null, $maxDepth = null) : array

将此集合递归地转换为数组。

  • 标量值按原样返回,
  • 对象以类名 => 属性(名称 => 值)的形式返回,只返回此类可访问的属性,
  • 数组或可遍历对象以数组的形式返回,
  • 对于其他任何东西,返回调用 gettype($input) 的结果

如果指定,$maxItemsPerCollection 将只保留指定数量的项在集合中,如果原始集合更长,则在末尾附加新元素 '>>>'。

如果指定,$maxDepth 将只保留指定的 n 层嵌套,一旦达到最大嵌套级别,则用 '^^^' 替换元素。

如果遇到具有重复键的集合,则重复键(除第一个之外)将更改为格式 originalKey//duplicateCounter,其中 duplicateCounter 从第一次重复的 1 开始。所以 [0 => 1, 0 => 2] 将变为 [0 => 1, '0//1' => 2]

Collection::from([1, 3, 3, 2])->dump(); //[1, 3, 3, 2]
$collection = Collection::from(
    [
        [
            [1, [2], 3],
            ['a' => 'b'],
            new ArrayIterator([1, 2, 3])
        ],
        [1, 2, 3],
        new ArrayIterator(['a', 'b', 'c']),
        true,
        new \DusanKasan\Knapsack\Tests\Helpers\Car('sedan', 5),
        \DusanKasan\Knapsack\concat([1], [1])
    ]
);

$collection->dump(2, 3);
//[
//    [
//        [1, '^^^', '>>>'],
//        ['a' => 'b'],
//        '>>>'
//    ],
//    [1, 2, '>>>'],
//    '>>>'
//]

$collection->dump();
//[
//    [
//        [1, [2], 3],
//        ['a' => 'b'],
//        [1, 2, 3]
//    ],
//    [1, 2, 3],
//    ['a', 'b', 'c'],
//    true,
//    [
//        'DusanKasan\Knapsack\Tests\Helpers\Car' => [
//            'numberOfSeats' => 5,
//        ],
//    ],
//    [1, '0//1' => 1]
//]
dump([1, 3, 3, 2], 2); // [1, 3, '>>>']

each(callable $function) : Collection

返回一个懒加载集合,其中为每个项执行 $function(value, key)。

Collection::from([1, 2, 3, 4, 5])
    ->each(function ($i) {
        echo $i . PHP_EOL;
    })
    ->toArray(); //[1, 2, 3, 4, 5]

//1
//2
//3
//4
//5
each([1, 2, 3, 4, 5], function ($v) {echo $v . PHP_EOL;});

//1
//2
//3
//4
//5

every(callable $function) : bool

如果 $function(value, key) 对于集合中的每个项都返回 true,则返回 true,否则返回 false。

Collection::from([1, 3, 3, 2])
    ->every(function ($v) {
        return $v < 3;
    }); //false
Collection::from([1, 3, 3, 2])
    ->every(function ($v, $k) {
       return $v < 4 && $k < 2;
    }); //false
every([1, 3, 3, 2], function ($v) {return $v < 5;}); //true

except(iterable $keys) : Collection

返回一个懒加载集合,其中不包含与 $keys 中的任何键关联的项。

Collection::from(['a' => 1, 'b' => 2])
    ->except(['a'])
    ->toArray(); //['b' => 2]
toArray(except(['a' => 1, 'b' => 2], ['a'])); //['b' => 2]

extract(mixed $keyPath) : Collection

返回一个懒加载集合,其中包含通过点分隔的键路径从 $collection 项中提取的数据。支持 * 通配符。如果键包含 \ 或 *,则必须使用 \ 字符进行转义。

$collection = Collection::from([['a' => ['b' => 1]], ['a' => ['b' => 2]], ['c' => ['b' => 3]]])
$collection->extract('a.b')->toArray(); //[1, 2]
$collection->extract('*.b')->toArray(); //[1, 2, 3]
toArray(extract([['a' => ['b' => 1]], ['a' => ['b' => 2]]], 'a.b')); //[1, 2]

filter(callable $function = null) : Collection

返回一个懒加载集合,其中包含使 $function(value, key) 返回 true 的项。

Collection::from([1, 3, 3, 2])
    ->filter(function ($value) {
        return $value > 2;
    })
    ->values()
    ->toArray(); //[3, 3]
Collection::from([1, 3, 3, 2])
    ->filter(function ($value, $key) {
        return $value > 2 && $key > 1;
    })
    ->toArray(); //[2 => 3]
toArray(values(filter([1, 3, 3, 2], function ($value) {return $value > 2;}))); //[3, 3]

如果没有提供 $function,则使用 \DusanKasan\Knapsack\identity,因此会移除所有假值。

Collection::from([0, 0.0, false, null, "", []])
    ->filter()
    ->isEmpty(); //true
isEmpty(values(filter([0, 0.0, false, null, "", []]))); //true

find(callable $function, mixed $ifNotFound = null, bool $convertToCollection = false) : mixed|Collection

返回第一个使 $function(value, key) 返回 true 的值。如果没有项匹配,则返回 $ifNotFound。如果 $convertToCollection 为 true 并且返回值是可迭代的,则返回 Collection 实例。

Collection::from([1, 3, 3, 2])
    ->find(function ($value) {
       return $value < 3;
    }); //1
Collection::from([1, 3, 3, 2])
    ->find(function ($value) {
       return $value > 3;
    }, 10); //10
Collection::from([1, 3, 3, 2])
    ->find(function ($value, $key) {
      return $value < 3 && $key > 1;
    }); //2
//if the output can be converted to Collection (it's array or Traversable), it will be.
Collection::from([1, [4, 5], 3, 2])
    ->find(function ($value) {
      return is_array($value);
    }, [], true)
    ->size(); //2 
find([1, 3, 3, 2], function ($value) {return $value > 2;}); //3

first(bool $convertToCollection = false) : mixed|Collection

返回集合中的第一个值或抛出 ItemNotFound,如果集合为空。如果 $convertToCollection 为 true 并且返回值是可迭代的,则返回 Collection 实例。

Collection::from([1, 2, 3])->first(); //1
Collection::from([[1], 2, 3])->first(); //[1]
Collection::from([])->first(); //throws ItemNotFound
first([1, 2, 3]); //1

flatten(int $depth = -1) : Collection

返回一个懒加载集合,其中包含一个或多个级别的嵌套被扁平化。如果没有传递 $depth 值,则移除所有嵌套。

Collection::from([1,[2, [3]]])
    ->flatten()
    ->values() //1, 2 and 3 have all key 0
    ->toArray(); //[1, 2, 3]
Collection::from([1,[2, [3]]])
    ->flatten(1)
    ->values() //1, 2 and 3 have all key 0
    ->toArray(); //[1, 2, [3]]
toArray(values(flatten([1, [2, [3]]]))); //[1, 2, 3]

flip() : Collection

返回一个懒加载集合,其中键和值被颠倒。

Collection::from(['a' => 0, 'b' => 1])
    ->flip()
    ->toArray(); //['a', 'b']
toArray(flip(['a' => 0, 'b' => 1])); //['a', 'b']

frequencies() : Collection

返回一个集合,其键是此集合中的不同项,其值是每个值的出现次数。

Collection::from([1, 3, 3, 2])
    ->frequencies()
    ->toArray(); //[1 => 1, 3 => 2, 2 => 1]
toArray(frequencies([1, 3, 3, 2])); //[1 => 1, 3 => 2, 2 => 1]

get(mixed $key, bool $convertToCollection = false) : mixed|Collection

返回键 $key 的值。如果有多个值具有此键,则返回第一个。如果没有值具有此键,则抛出 ItemNotFound。如果 $convertToCollection 为 true 并且返回值是可迭代的,则返回 Collection 实例。

Collection::from([1, 3, 3, 2])->get(2); //3
Collection::from([1, [1, 2]])->get(1, true)->toArray(); //[1, 2]
Collection::from([1, 3, 3, 2])->get(5); //throws ItemNotFound
get([1, 3, 3, 2], 2); //3

getOrDefault(mixed $key, mixed $default = null, bool $convertToCollection = false) : mixed|Collection

根据键 $key 获取值。如果有多个值具有此键,返回第一个。如果没有值具有此键,返回 $default。如果 $convertToCollection 为 true 且返回值是可迭代的,则返回 Collection 实例。

Collection::from([1, 3, 3, 2])->getOrDefault(2); //3
Collection::from([1, 3, 3, 2])->getOrDefault(5); //null
Collection::from([1, 3, 3, 2])->getOrDefault(5, 'asd'); //'asd'
Collection::from([1, 3, 3, 2])->getOrDefault(5, [1, 2], true)->toArray(); //[1, 2]
getOrDefault([1, 3, 3, 2], 5, 'asd'); //'asd'

groupBy(callable $function) : Collection

返回一个集合,其中项目根据 $function(value, key) 的返回值分组。

Collection::from([1, 2, 3, 4, 5])
    ->groupBy(function ($value) {
        return $value % 2;
    })
    ->toArray(); //[1 => [1, 3, 5], 0 => [2, 4]]
toArray(groupBy([1, 2, 3, 4, 5], function ($value) {return $value % 2;})); //[1 => [1, 3, 5], 0 => [2, 4]]

groupByKey(mixed $key) : Collection

返回一个集合,其中项目根据给定键的值分组。

Collection::from([
        ['letter' => 'A', 'type' => 'caps'],
        ['letter' => 'a', 'type' => 'small'],
        ['letter' => 'B', 'type' => 'caps'],
    ])
    ->groupByKey('type')
    ->map('DusanKasan\Knapsack\toArray')
    ->toArray();
    // [ 'caps' => [['letter' => 'A', 'type' => 'caps'], ...], 'small' => [['letter' => 'a', 'type' => 'small']]]
$data = [
    ['letter' => 'A', 'type' => 'caps'],
    ['letter' => 'a', 'type' => 'small'],
    ['letter' => 'B', 'type' => 'caps'],
];
toArray(map(groupByKey($data, 'type'), 'toArray')); //[ 'caps' => [['letter' => 'A', 'type' => 'caps'], ...], 'small' => [['letter' => 'a', 'type' => 'small']]]

has(mixed $key) : bool

检查 $key 是否存在于该集合中。

Collection::from(['a' => 1])->has('a'); //true
has(['a' => 1], 'a'); //true

indexBy(callable $function) : Collection

通过将此集合的每个项的键改为 $function(value, key) 的结果来返回一个惰性集合。

Collection::from([1, 3, 3, 2])
    ->indexBy(function ($v) {
        return $v;
    })
    ->toArray(); //[1 => 1, 3 => 3, 2 => 2]
toArray(indexBy([1, 3, 3, 2], '\DusanKasan\Knapsack\identity')); //[1 => 1, 3 => 3, 2 => 2]

interleave(iterable ...$collections) : Collection

返回一个惰性集合,其中包含来自第一个集合的第一个元素,来自第二个集合的第一个元素,来自第一个集合的第二个元素,依此类推。适用于任何数量的参数。

Collection::from([1, 3, 3, 2])
    ->interleave(['a', 'b', 'c', 'd', 'e'])
    ->values()
    ->toArray(); //[1, 'a', 3, 'b', 3, 'c', 2, 'd', 'e']
toArray(interleave([1, 3, 3, 2], ['a', 'b', 'c', 'd', 'e'])); //[1, 'a', 3, 'b', 3, 'c', 2, 'd', 'e']

interpose(mixed $separator) : Collection

返回一个惰性集合,该集合包含此集合的项,并由 $separator 项分隔。

Collection::from([1, 2, 3])
    ->interpose('a')
    ->values() // we must reset the keys, because each 'a' has undecided key
    ->toArray(); //[1, 'a', 2, 'a', 3]
toArray(interpose([1, 2, 3], 'a')); //[1, 'a', 2, 'a', 3] 

intersect(iterable ...$collections) : Collection

返回一个惰性集合,其中包含在 $collection 和所有其他参数中的项,键来自第一个集合。注意,...$collections 是非惰性迭代的。

Collection::from([1, 2, 3])
    ->intersect([1, 3])
    ->toArray(); //[1, 2 => 3]
toArray(intersect([1, 2, 3],[1, 3])); //[1, 2 => 3] 

isEmpty() : bool

如果集合为空,则返回 true。否则返回 false。

Collection::from([1, 3, 3, 2])->isEmpty(); //false
isEmpty([1]); //false

isNotEmpty() : bool

isEmpty 的对立面

Collection::from([1, 3, 3, 2])->isNotEmpty(); //true
isNotEmpty([1]); //true

keys() : Collection

返回一个惰性集合,包含此集合的键。

Collection::from(['a' => [1, 2], 'b' => [2, 3]])
    ->keys()
    ->toArray(); //['a', 'b']
toArray(keys(['a' => [1, 2], 'b' => [2, 3]])); //['a', 'b']

last(bool $convertToCollection = false) : mixed|Collection

返回集合中的最后一个值或抛出 ItemNotFound 异常,如果集合为空。如果 $convertToCollection 为 true 且返回值是可迭代的,则返回 Collection 实例。

Collection::from([1, 2, 3])->last(); //3
Collection::from([1, 2, [3]])->last(true)->toArray(); //[1]
Collection::from([])->last(); //throws ItemNotFound
last([1, 2, 3]); //3

map(callable $function) : Collection

返回一个集合,其中每个值都变为执行 $function(value, key) 的输出。

Collection::from([1, 3, 3, 2])
    ->map(function ($value) {
        return $value + 1;
    })
    ->toArray(); //[2, 4, 4, 3]
toArray(map([1, 3, 3, 2], '\DusanKasan\Knapsack\increment')); //[2, 4, 4, 3]

mapcat(callable $mapper) : Collection

返回一个惰性集合,它是调用 map($mapper(value, key)) 然后扁平化 1 的结果。

Collection::from([1, 3, 3, 2])
    ->mapcat(function ($value) {
        return [[$value]];
    })
    ->values()
    ->toArray(); //[[1], [3], [3], [2]]
Collection::from([1, 3, 3, 2])
    ->mapcat(function ($key, $value) {
        return [[$key]];
    })
    ->values()
    ->toArray(); //[[0], [1], [2], [3]]
toArray(values(mapcat([1, 3, 3, 2], function ($value) {return [[$value]];}))); //[[1], [3], [3], [2]]

max() : mixed

返回集合中的最大值。

Collection::from([1, 2, 3, 2])->max(); //3
Collection::from([])->max(); //null
max([1, 2, 3, 2]); //3

min() : mixed

返回集合中的最小值。

Collection::from([1, 2, 3, 2])->min(); //1
Collection::from([])->min(); //null
min([1, 2, 3, 2]); //1

only(iterable $keys) : Collection

返回一个惰性集合,包含与 $keys 中的任何键关联的项目。

Collection::from(['a' => 1, 'b' => 2])
    ->only(['b'])
    ->toArray(); //['b' => 2]
toArray(only(['a' => 1, 'b' => 2], ['b'])); //['b' => 2]

partition(int $numberOfItems, int $step = 0, iterable $padding = []) : Collection

返回一个惰性集合,其中包含每个 $numberOfItems 项的集合,每隔 $step 步。如果未提供 $step,则默认为 $numberOfItems,即分区不重叠。如果提供了 $padding 集合,则使用其元素按需完成最后一个分区,以达到 $numberOfItems 项。如果没有足够的填充元素,则返回一个包含少于 $numberOfItems 项的分区。

Collection::from([1, 3, 3, 2])
    ->partition(3, 2, [0, 1])
    ->toArray(); //[[1, 3, 3], [2 => 3, 3 => 2, 0 => 0]]
Collection::from([1, 3, 3, 2])
    ->partition(3, 2)
    ->toArray(); //[[1, 3, 3], [2 => 3, 3 => 2]]
Collection::from([1, 3, 3, 2])
    ->partition(3)
    ->toArray(); //[[1, 3, 3], [3 => 2]]
toArray(partition([1, 3, 3, 2], 3)); //[[1, 3, 3], [3 => 2]]

partitionBy(callable $function) : Collection

创建一个惰性集合,该集合通过每次 $function(value, key) 返回不同的结果来分区此集合。

Collection::from([1, 3, 3, 2])
    ->partitionBy(function ($v) {
        return $v % 3 == 0;
    })
    ->toArray(); //[[1], [1 => 3, 2 => 3], [3 => 2]]
toArray(partitionBy([1, 3, 3, 2], function ($value) {return $value % 3 == 0;})); //[[1], [1 => 3, 2 => 3], [3 => 2]]

prepend(mixed $item, mixed $key = null) : Collection

返回一个惰性集合,其中包含此集合的项,并将 $item 添加为第一个元素。其键将为 $key。如果未提供 $key,则其键将为下一个数值索引。

Collection::from([1, 3, 3, 2])
    ->prepend(1)
    ->values() //both 1 have 0 key
    ->toArray(); //[1, 1, 3, 3, 2]
Collection::from([1, 3, 3, 2])
    ->prepend(1, 'a')
    ->toArray(); //['a' => 1, 0 => 1, 1 => 3, 2 => 3, 3 => 2]

printDump(int $maxItemsPerCollection = null, $maxDepth = null) : Collection

在 $input 上调用 dump,然后使用 var_export 打印它。返回集合。有关参数和输出文档,请参阅 dump 函数。

Collection::from([1, 3, 3, 2])
    ->printDump()
    ->toArray(); //[1, 3, 3, 2]
toArray(printDump([1, 3, 3, 2])); //[1, 3, 3, 2]

realize() : Collection

实现集合 - 通过迭代并存储键/值将惰性集合转换为非惰性集合。

$helper->setValue(1); 

$realizedCollection = Collection::from([1, 3, 3, 2])
    ->map(function ($item) use ($helper) {return $helper->getValue() + $item;})
    ->realize();
    
$helper->setValue(10);
$realizedCollection->toArray(); // [2, 4, 4, 3]
toArray(realize([1, 3, 3, 2])); //[1, 3, 3, 2]

reduce(callable $function, mixed $start, bool $convertToCollection = false) : mixed|Collection

通过迭代集合并调用$function(tmp, value, key),同时传递起始和当前键/项作为参数,将集合减少到单个值。可调用函数的输出用作下一次迭代的起始值。可调用函数在最后一个元素上的输出是此函数的返回值。如果$convertToCollection为true且返回值是可迭代的,则返回Collection的实例。

Collection::from([1, 3, 3, 2])
    ->reduce(
        function ($tmp, $i) {
            return $tmp + $i;
        }, 
        0
    ); //9
    
Collection::from([1, 3, 3, 2])
    ->reduce(
        function ($tmp, $i) {
            $tmp[] = $i + 1;
            return $tmp;
        }, 
        [],
        true
    )
    ->first(); //2
reduce([1, 3, 3, 2], function ($tmp, $value) {return $tmp + $value;}, 0); //9

reduceRight(callable $function, mixed $start, bool $convertToCollection = false) : mixed|Collection

类似于reduce,但从最后一个元素走到第一个元素。如果$convertToCollection为true且返回值是可迭代的,则返回Collection的实例。

Collection::from([1, 3, 3, 2])
    ->reduceRight(
        function ($tmp, $i) {
            return $tmp + $i;
        }, 
        0
    ); //9
    
Collection::from([1, 3, 3, 2])
    ->reduce(
        function ($tmp, $i) {
            $tmp[] = $i + 1;
            return $tmp;
        }, 
        [],
        true
    )
    ->first(); //3
reduceRight([1, 3, 3, 2], function ($tmp, $value) {return $tmp + $value;}, 0); //9

reductions(callable $reduction, mixed $start) : Collection

返回一个包含缩减步骤的惰性集合。

Collection::from([1, 3, 3, 2])
    ->reductions(function ($tmp, $i) {
        return $tmp + $i;
    }, 0)
    ->toArray(); //[1, 4, 7, 9]
toArray(reductions([1, 3, 3, 2], function ($tmp, $value) {return $tmp + $value;}, 0)); //[1, 4, 7, 9]

reject(callable $filter) : Collection

返回一个惰性集合,其中包含对于$filter(value, key)返回false的项。

Collection::from([1, 3, 3, 2])
    ->reject(function ($value) {
        return $value > 2;
    })
    ->toArray(); //[1, 3 => 2]
Collection::from([1, 3, 3, 2])
    ->reject(function ($value, $key) {
        return $value > 2 && $key > 1;
    })
    ->toArray(); //[1, 1 => 3, 3 => 2]
toArray(reject([1, 3, 3, 2], function ($value) {return $value > 2;})); //[1, 1 => 3, 3 => 2]

replace(iterable $replacementMap) : Collection

返回一个惰性集合,其中此集合的项与$replacementMap中的任何键相等时,将替换为其值。

Collection::from([1, 3, 3, 2])
    ->replace([3 => 'a'])
    ->toArray(); //[1, 'a', 'a', 2]
toArray(replace([1, 3, 3, 2], [3 => 'a'])); //[1, 'a', 'a', 2]

replaceByKeys(iterable $replacementMap) : Collection

返回一个惰性集合,其中包含来自$collection的项,但具有在$replacementMap的键中找到的键的项被其值替换。

Collection::from([1, 3, 3, 2])
    ->replace([3 => 'a'])
    ->toArray(); //[1, 3, 3, 'a']
toArray(replace([1, 3, 3, 2], [3 => 'a'])); //[1, 3, 3, 'a']

reverse() : Collection

返回一个非惰性集合,其中包含此集合中的项的逆序。

Collection::from([1, 2, 3])
    ->reverse()
    ->toArray(); //[2 => 3, 1 => 2, 0 => 1]
toArray(reverse([1, 2, 3])); //[2 => 3, 1 => 2, 0 => 1]

second(bool $convertToCollection = false) : mixed|Collection

返回$collection的第二项或抛出ItemNotFound异常,如果$collection为空或只有一个项。如果$convertToCollection为true且返回值是可迭代的,则将其转换为Collection。

Collection::from([1, 3, 3, 2])->second(); //3
second([1, 3]); //3

shuffle() : Collection

返回一个从此集合中抽取的项的随机集合。

Collection::from([1, 3, 3, 2])
    ->shuffle()
    ->toArray(); //something like [2 => 3, 0 => 1, 3 => 2, 1 => 3]
toArray(shuffle([1, 3, 3, 2])); //something like [2 => 3, 0 => 1, 3 => 2, 1 => 3]

size() : int

返回此集合中的项数。

Collection::from([1, 3, 3, 2])->size(); //4
size([1, 3, 3, 2]); //4

sizeIsBetween(int $fromSize, int $toSize) : bool

检查此集合是否有介于$fromSize到$toSize项之间。$toSize可以小于$fromSize。

Collection::from([1, 3, 3, 2])->sizeIsBetween(3, 5); //true
sizeIsBetween([1, 3, 3, 2], 3, 5); //true

sizeIs(int $size) : bool

检查此集合是否有恰好$size项。

Collection::from([1, 3, 3, 2])->sizeIs(4); //true
sizeIs([1, 3, 3, 2], 4); //true

sizeIsGreaterThan(int $size) : bool

检查此集合是否有超过$size项。

Collection::from([1, 3, 3, 2])->sizeIsGreaterThan(3); //true
sizeIsGreaterThan([1, 3, 3, 2], 3); //true

sizeIsLessThan(int $size) : bool

检查此集合是否有少于$size项。

Collection::from([1, 3, 3, 2])->sizeIsLessThan(5); //true
sizeIsLessThan([1, 3, 3, 2], 5); //true

slice(int $from, int $to) : Collection

返回一个惰性集合,包含从原始集合中从项目号$from到项目号$to的项(包括$from和$to)。在$from之前的项也被实现,只是没有返回。

Collection::from([1, 2, 3, 4, 5])
    ->slice(2, 4)
    ->toArray(); //[2 => 3, 3 => 4]
Collection::from([1, 2, 3, 4, 5])
    ->slice(4)
    ->toArray(); //[4 => 5]
toArray(slice([1, 2, 3, 4, 5], 4)); //[4 => 5]

some(callable $function) : bool

如果$function(value, key)对此集合中的至少一个项返回true,则返回true,否则返回false。

Collection::from([1, 3, 3, 2])
    ->some(function ($value) {
       return $value < 3;
    }); //true
Collection::from([1, 3, 3, 2])
    ->some(function ($value, $key) {
       return $value < 4 && $key < 2;
    }); //true
some([1, 3, 3 ,2], function ($value) {return $value < 3;}); //true

sort(callable $function) : Collection

返回使用$function(value1, value2, key1, key2)排序的集合。如果第一个参数被认为分别小于、等于或大于第二个参数,则$function应返回一个小于、等于或大于零的整数。

Collection::from([3, 1, 2])
    ->sort(function ($a, $b) {
        return $a > $b;
    })
    ->toArray(); //[1 => 1, 2 => 2, 0 => 3]
Collection::from([3, 1, 2])
    ->sort(function ($v1, $v2, $k1, $k2) {
        return $v1 < $v2;
    })
    ->toArray(); //[2 => 2, 1 => 1, 0 => 3]
toArray(sort([3, 1, 2], function ($a, $b) {return $a > $b;})); //[1 => 1, 2 => 2, 0 => 3]

splitAt(int $position) : Collection

返回一个包含惰性集合的集合:[take($position), drop($position)]。

Collection::from([1, 3, 3, 2])
    ->splitAt(2)
    ->toArray(); //[[1, 3], [2 => 3, 3 => 2]]
toArray(splitAt([1, 3, 3, 2], 2)); //[[1, 3], [2 => 3, 3 => 2]]

splitWith(callable $function) : Collection

返回一个包含惰性集合的集合:[takeWhile($function(value, key)), dropWhile($function(value, key))]。

Collection::from([1, 3, 3, 2])
    ->splitWith(function ($value) {
        return $value < 3;
    })
    ->toArray(); //[[1], [1 => 3, 2 => 3, 3 => 2]]
Collection::from([1, 3, 3, 2])
    ->splitWith(function ($value, $key) {
        return $key < 2 && $value < 3;
    })
    ->toArray(); //[[1], [1 => 3, 2 => 3, 3 => 2]]
toArray(splitWith([1, 3, 3, 2], function ($value) {return $value < 3;})); //[[1], [1 => 3, 2 => 3, 3 => 2]]

sum() : int|float

返回此集合中所有值的总和。

Collection::from([1, 2, 3])->sum(); //6
Collection::from([1, 2, 3, 1.5])->sum(); //7.5
Collection::from([])->sum(); //0
sum([1, 2, 3]); //6

take(int $numberOfItems) : Collection

一种切片形式,返回前$numberOfItems项。

Collection::from([1, 2, 3, 4, 5])
    ->take(2)
    ->toArray(); //[1, 2]
toArray(take([1, 2, 3, 4, 5], 2)); //[1, 2]

takeNth(int $step) : Collection

返回一个包含此集合中每第n个项的惰性集合。

Collection::from([1, 3, 3, 2])
    ->takeNth(2)
    ->toArray(); //[1, 2 => 3]
toArray(takeNth([1, 3, 3, 2], 2)); //[1, 2 => 3]

takeWhile(callable $function) : Collection

返回一个从集合的开始到第一个使$function(value, key)返回false的项的惰性集合。

Collection::from([1, 3, 3, 2])
    ->takeWhile(function ($value) {
        return $value < 3;
    })
    ->toArray(); //[1]
Collection::from([1, 3, 3, 2])
    ->takeWhile(function ($value, $key) {
        return $key < 2 && $value < 3;
    })
    ->toArray(); //[1]
toArray(takeWhile([1, 3, 3, 2], function ($value) {return $value < 3;})); //[1]

transform(callable $transformer) : Collection

使用$transformer可调用函数对其自身进行操作,该函数接受一个Collection并返回Collection。这允许创建独立的可重用算法。

$transformer = function (Collection $collection) {
    return $collection
        ->filter(function ($item) {
            return $item > 1;
        })
        ->map('\DusanKasan\Knapsack\increment');
};

Collection::from([1, 3, 3, 2])
    ->transform($transformer)
    ->toArray(); //[4, 4, 3]

toArray() : array

递归地将集合转换为数组。显然,这不是惰性的,因为必须实现所有项。内部调用iterator_to_array。

Collection::from([1, 3, 3, 2])->toArray(); //[1, 3, 3, 2]
toArray([1, 3, 3, 2]); //[1, 3, 3, 2]

toString() : string

通过将此集合的值连接成字符串来返回一个字符串。

Collection::from([1, 'a', 3, null])->toString(); //'1a3'
Collection::from([])->toString(); //''
toString([1, 'a', 3, null]); //'1a3'

transpose(iterable $collection) : string

通过交换每一行和对应的列返回一个非懒加载的集合。输入必须是一个多维集合,否则会抛出 InvalidArgumentException。

$arr = Collection::from([
    new Collection([1, 2, 3]),
    new Collection([4, 5, new Collection(['foo', 'bar'])]),
    new Collection([7, 8, 9]),
])->transpose()->toArray();

// $arr =
// [
//    new Collection([1, 4, 7]),
//    new Collection([2, 5, 8]),
//    new Collection([3, new Collection(['foo', 'bar']), 9]),
// ]

zip(iterable ...$collections) : Collection

返回一个从该集合和每个传入集合的第 n 个位置开始的非懒加载集合的懒加载集合。当任何集合在第 n 个位置没有项目时停止。

Collection::from([1, 2, 3])
    ->zip(['a' => 1, 'b' => 2, 'c' => 4])
    ->map('\DusanKasan\Knapsack\toArray')
    ->toArray(); //[[1, 'a' => 1], [1 => 2, 'b' => 2], [2 => 3, 'c' => 4]]

Collection::from([1, 2, 3])
    ->zip(['a' => 1, 'b' => 2])
    ->map('\DusanKasan\Knapsack\toArray')
    ->toArray(); //[[1, 'a' => 1], [1 => 2, 'b' => 2]]
toArray(map(zip([1, 2, 3], ['a' => 1, 'b' => 2, 'c' => 4]), '\DusanKasan\Knapsack\toArray')); //[[1, 'a' => 1], [1 => 2, 'b' => 2], [2 => 3, 'c' => 4]]

实用函数

这些是与 Knapsack 一起打包的函数,可以在您过渡到函数式编程时使您的生活更轻松。

identity(mixed $value)

返回 $value

$value === identity($value); //true

compare(mixed $a, mixed $b)

默认比较函数。当 $a 在逻辑上“小于”、“等于”或“大于”$b 时,返回负数、零或正数。

compare(1, 2); //-1

increment(int $value)

返回 $value 加一的值。

increment(0) === 1; //true

decrement(int $value)

返回 $value 减一的值。

decrement(2) === 1; //true