Skip to content

Commit 2bbfd9f

Browse files
committed
add all files
1 parent e15ac88 commit 2bbfd9f

File tree

10 files changed

+547
-0
lines changed

10 files changed

+547
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
vendor

Readme.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
# Array Utilities
3+
4+
Useful functions for those programmers who like to do array transformations and like to think in higher-order concepts.

src/Ve/functions/categorize.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
namespace Ve;
4+
5+
/**
6+
* this function is for when the property is an object which should be compared by identity
7+
* (this could be doctrine entities with a many-to-one relation to a type table)
8+
*
9+
* You would not be able to use the "group" functions because an object cannot be a key in an associative array
10+
*
11+
* @param Traversable $objects
12+
* @param string $property to compare by object identity
13+
* @param string $collectionName key under which the objects will be stored in the category
14+
*
15+
* @return [
16+
* [
17+
* $propertyName => $propertyValue
18+
* $collectionName => $categorizedObjects
19+
* ]
20+
* ...
21+
* ]
22+
*/
23+
function categorizeByPropertyIdentity($objects, string $property, string $collectionName = 'objects'): array
24+
{
25+
$result = [];
26+
27+
foreach ($objects as $obj)
28+
{
29+
foreach ($result as &$category)
30+
{
31+
if ($category[$property] === $obj->$property)
32+
{
33+
// add to existing category
34+
$category[$collectionName][] = $obj;
35+
continue 2;
36+
}
37+
}
38+
// create a new category
39+
$result[] = [
40+
$property => $obj->$property,
41+
$collectionName => [$obj]
42+
];
43+
}
44+
45+
return $result;
46+
}

src/Ve/functions/filter.php

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
<?php
2+
3+
/**
4+
* functions:
5+
* - filter
6+
* - reject
7+
* - where
8+
* - whereNot
9+
* - find
10+
* - findWhere
11+
*/
12+
13+
namespace Ve;
14+
15+
/**
16+
* this exists because array_filter can't call methods
17+
*/
18+
function filter($objects, string $method): array
19+
{
20+
$result = [];
21+
foreach ($objects as $obj)
22+
{
23+
if (call_user_func([$obj, $method]))
24+
{
25+
$result[] = $obj;
26+
}
27+
}
28+
return $result;
29+
}
30+
31+
/**
32+
* opposite of filter
33+
*/
34+
function reject($objects, string $method): array
35+
{
36+
$result = [];
37+
foreach ($objects as $obj)
38+
{
39+
if (! call_user_func([$obj, $method]))
40+
{
41+
$result[] = $obj;
42+
}
43+
}
44+
return $result;
45+
}
46+
47+
/**
48+
* logic like filter but is guaranteed to return a single result, else an exeption is thrown
49+
*/
50+
function find($objects, callable $fn)
51+
{
52+
foreach ($objects as $obj)
53+
{
54+
if (call_user_func($fn, $obj))
55+
{
56+
return $obj;
57+
}
58+
}
59+
throw new \LengthException;
60+
}
61+
62+
63+
/**
64+
* Same as self::where, except guarantees to find 1 instance else an exception is thrown
65+
* Short-circuit optimization possible
66+
*/
67+
function findWhere($objects, array $keyValuePair)
68+
{
69+
$resultCollection = where($objects, $keyValuePair);
70+
71+
if (count($resultCollection) !== 1)
72+
{
73+
throw new \LengthException;
74+
}
75+
76+
return $resultCollection[0];
77+
}
78+
79+
/**
80+
* Filters the input by property
81+
*
82+
* Possible improvement: allow multiple key-value pairs
83+
*
84+
* @param array|Traversable $objects
85+
*/
86+
function where($objects, array $keyValuePair): array
87+
{
88+
$property = array_keys($keyValuePair)[0];
89+
$value = array_values($keyValuePair)[0];
90+
91+
$result = [];
92+
93+
foreach ($objects as $obj)
94+
{
95+
if (is_object($obj))
96+
{
97+
if (property_exists($obj, $property))
98+
{
99+
if ($obj->$property === $value)
100+
{
101+
$result[] = $obj;
102+
}
103+
}
104+
elseif (method_exists($obj, $property))
105+
{
106+
if (call_user_func([$obj, $method]) === $value)
107+
{
108+
$result[] = $obj;
109+
}
110+
}
111+
else
112+
{
113+
throw new \InvalidArgumentException;
114+
}
115+
}
116+
elseif (is_array($obj))
117+
{
118+
if ($obj[$property] === $value)
119+
{
120+
$result[] = $obj;
121+
}
122+
}
123+
else
124+
{
125+
throw new \InvalidArgumentException;
126+
}
127+
}
128+
return $result;
129+
}
130+
131+
/**
132+
* Filters the input by property
133+
*
134+
* Possible improvement: allow multiple key-value pairs
135+
*
136+
* @param array|Traversable $objects
137+
*/
138+
function whereNot($objects, array $keyValuePair): array
139+
{
140+
$property = array_keys($keyValuePair)[0];
141+
$value = array_values($keyValuePair)[0];
142+
143+
$result = [];
144+
145+
foreach ($objects as $obj)
146+
{
147+
if (is_object($obj))
148+
{
149+
if (property_exists($obj, $property))
150+
{
151+
if ($obj->$property !== $value)
152+
{
153+
$result[] = $obj;
154+
}
155+
}
156+
elseif (method_exists($obj, $property))
157+
{
158+
if (call_user_func([$obj, $method]) !== $value)
159+
{
160+
$result[] = $obj;
161+
}
162+
}
163+
else
164+
{
165+
throw new \InvalidArgumentException;
166+
}
167+
}
168+
elseif (is_array($obj))
169+
{
170+
if ($obj[$property] !== $value)
171+
{
172+
$result[] = $obj;
173+
}
174+
}
175+
else
176+
{
177+
throw new \InvalidArgumentException;
178+
}
179+
}
180+
return $result;
181+
}

src/Ve/functions/group.php

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
3+
namespace Ve;
4+
5+
/**
6+
* @var objects array|traversable of objects
7+
* @var $properties property to group by.
8+
* If multiple are given they are treated as nested properties ($obj->prop1->prop2->prop3)
9+
* @return array nested in groups
10+
*/
11+
function groupByProperty($objects, string ...$properties): array
12+
{
13+
$result = [];
14+
foreach ($objects as $obj)
15+
{
16+
$value = $obj;
17+
foreach ($properties as $prop)
18+
{
19+
$value = $value->$prop;
20+
}
21+
$result[$value][] = $obj;
22+
}
23+
return $result;
24+
}
25+
26+
function groupByMethod($objects, string $method): array
27+
{
28+
$result = [];
29+
foreach ($objects as $obj)
30+
{
31+
$result[call_user_func([$obj, $method])][] = $obj;
32+
}
33+
return $result;
34+
}
35+
36+
function groupByCallable($list, callable $callable): array
37+
{
38+
$result = [];
39+
foreach ($list as $var)
40+
{
41+
$result[call_user_func($callable, $var)][] = $var;
42+
}
43+
return $result;
44+
}
45+
46+
/**
47+
* @param Traversable|array $list
48+
* @param \Callable $equals
49+
* --> with signature function(var1, var2): bool
50+
* --> equality is assumed to be transitive
51+
*/
52+
function groupByEquality($list, callable $equals): array
53+
{
54+
$result = [];
55+
foreach ($list as $var)
56+
{
57+
foreach($result as &$group)
58+
{
59+
if (call_user_func($equals, $group[0], $var))
60+
{
61+
$group[] = $var;
62+
continue 2;
63+
}
64+
}
65+
$result[] = [$var]; // create a new group
66+
}
67+
return $result;
68+
}

src/Ve/functions/map.php

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php
2+
3+
namespace Ve;
4+
5+
/**
6+
* calls a method on all objects
7+
*
8+
* @param $objects array|Traversable
9+
* @param $method string
10+
*/
11+
function map($objects, string $method): array
12+
{
13+
$result = [];
14+
15+
foreach ($objects as $obj)
16+
{
17+
$result[] = $obj->$method();
18+
}
19+
20+
return $result;
21+
}
22+
23+
/**
24+
* gets a property from all objects
25+
*
26+
* @param $objects array|Traversable
27+
* @param $property string
28+
*/
29+
function pluck($objects, string $property): array
30+
{
31+
$result = [];
32+
33+
foreach ($objects as $obj)
34+
{
35+
$result[] = $obj->property;
36+
}
37+
38+
return $result;
39+
}
40+
41+
/**
42+
* array_map does not allow us to
43+
* (1) access keys of the input or
44+
* (2) determine the keys of the output
45+
* without getting rather creative with array_keys, array_flip
46+
* or using array_walk, which is impure and does not allow to create new keys
47+
*
48+
* this function can do both
49+
*
50+
* the callback MUST return an array (because of the output key)
51+
* the resulting arrays will be merged
52+
*/
53+
function mapWithKey(array $array, callable $fn)
54+
{
55+
$result = [];
56+
57+
foreach ($array as $key => $value)
58+
{
59+
$result += $fn($value, $key);
60+
}
61+
62+
return $result;
63+
}
64+
65+
/**
66+
* Helper to build and associative array of properties from a collection of objects,
67+
* e.g. from object ID's to object properties
68+
*/
69+
function buildAssoc(array $objects, string $keyProperty, string $valueProperty): array
70+
{
71+
$keys = pluck($objects, $keyProperty);
72+
$values = pluck($objects, $valueProperty);
73+
74+
return array_combine($keys, $values);
75+
}

0 commit comments

Comments
 (0)