Creating a PHP array with values from a function - php

I want to create an array with x elements, where each element is created by calling a function. I'm looking for an idiomatic way to do this that minimizes state, especially mutating state, and also minimizes imperativeness.
I have working code that does this task, more specifically it creates an array with 10 elements using a function that returns a random character.
array_map(
function() use ( $characters, $characterCount ) {
return $characters[mt_rand( 0, $characterCount - 1 )];
},
array_fill( 0, 10, null )
)
When starting with this I was looking for something like the following, but did not find it:
array_create(
function() {},
10
);

It is common to simply use a looping construct like:
$array = array();
for($i = 0; $i < 10; $i++) {
$array[] = randomfunction();
}
If you want to wrap this in a function, do something like:
function genArray($x, $func) {
$array = array();
for($i = 0; $i < $x; $i++) {
$array[] = $func();
}
return $array;
}
Then you can pass it the number of elements and which function to use!

Related

How to get all the unique combinations of array including blanks (order of items not relevant)

I have this array:
$array = array( 57, 53, 52 );
I want to get all the unique combinations of those numbers (order of the items not relevant).
I want a result along the lines of:
// 57
// 57, 53
// 57, 53, 52
// 53
// 52
// 52, 57
I am using this function, but this returns every combination of the values and as I don't care for the order they are all the same result just in a different order:
function my_function( $array ) {
$combinations = array();
$words = sizeof( $array );
$combos = 1;
for( $i = $words; $i > 0; $i-- ) {
$combos *= $i;
}
while( sizeof( $combinations ) < $combos ) {
shuffle($array);
$combo = implode( " ", $array );
if( !in_array( $combo, $combinations ) ) {
$combinations[] = $combo;
}
}
return $combinations;
}
print_r( my_function( $array ) );
How can I achieve this?
<?php
function my_function($array){
$combs = [[]]; // adding empty set for better code clarity
sort($array); // sort the array to avoid verbose code to handle duplicate combinations
$set = [];
foreach($array as $index => $element){
$temp = [];
foreach($combs as $curr_comb){
$new_comb = $curr_comb;
$new_comb[] = $element;
$hashed_comb = implode(",",$new_comb);
if(!isset($set[$hashed_comb])){
$temp[] = $new_comb;
$set[$hashed_comb] = true;
}
}
$combs = array_merge($combs,$temp);
}
return array_slice($combs,1); // removing the empty set initially added
}
print_r(my_function([57,53,52]));
print_r(my_function([3,3,3]));
Demo: https://3v4l.org/f3IHs
We add an empty combination []before to make the code look simple.
We generate combinations by adding current element to previous generated set of combinations. Like, first it's [] which later becomes [],[57] which in turn later(in next iteration of first foreach loop) becomes [],[57],[53],[57,53] and so on.
We do an implode() and insert in the set to remember the combination to avoid duplicacy.
Since order doesn't matter, it seems like we could work our way through in order. Start with the first number and find all combinations, then move on to the second as our starting number, and so on. And since I love recursive functions (function recursion is its own reward), this is how I'd go about it:
function unique_combinations( $array, $prefix = '' ) {
$combinations = array();
$count = count($array);
// I use a for loop just to count the number of times to run. Since I'm using array_shift, the array will keep getting smaller
for( $i = 0; $i < $count; $i++ ) {
$number = array_shift($array);
// Grab our current result (this number and any prefixes
$this_result = trim( "$prefix $number" );
$combinations[] = $this_result;
// Now, if the array still has numbers in it, run the function on those numbers and combine results
if ( count($array) > 0 ) {
$combinations = array_merge($combinations, unique_combinations( $array, $this_result ) );
}
}
return $combinations;
}
print_r( unique_combinations( [57,58,59] ) );
A similar and also pretty short recursive approach with a single anonymous function, sort and an early array_unique. Should give you what you want, for simplicity the values are sorted in ascending order:
// all the logic
$getAllCombinations = function($array) {
$result = [];
sort($array);
$getOrderedCombinations = function ($combination_base, &$result) use (&$getOrderedCombinations) {
array_push($result,$combination_base);
if(count($combination_base) > 1) {
foreach($combination_base as $key => $val) {
$newcombo = $combination_base;
unset($newcombo[$key]);
$getOrderedCombinations($newcombo,$result);
}
}
};
$getOrderedCombinations($array,$result);
return array_unique($result,SORT_REGULAR);
};
// execution
$array = array( 57, 53, 52 );
var_dump($getAllCombinations($array));

PHP Array of Methods and Parameters

I'm passing an array of methods and parameters to my object. The array can be any size with any number of methods and/or parameters. In between the methods are the parameters.
EDIT: Sorry that this was not clear. The parameters following a method are for THAT method. So in the first example below method1 has two parameters (param1 and param2), method2 has two parameters (param1 and param2) and method3 has one parameter (param).
Here are some examples:
array = ["method1","param1","param2","method2","param1","param2","method3","param"];
array = ["method1","param1","param2","method2","param"];
array = ["method","param"];
I can pull the methods from the array using method_exists but I'm trying to pull the parameters from the array. This is what I've got so far:
// Loop thru $array to find methods
$methods = array();
for($i=0; $i < count($array); $i++) {
if(method_exists($this,$array[$i]) === TRUE) {
$methods[] = $i;
}
}
// Get parameters for methods
// If there is only one method take the remaining array values
// else get the parameters in between the methods
if(count($methods) == 1) {
$parameters = array_slice($array,1,count($array));
} else {
??
}
How can I grab the array values for parameters that match up to the methods when the array values for methods are variable?
You are close, but I believe you only want to process the array once. Remember - all of your array values are either "methods" OR "parameters". Therefore, if you are able to find "methods", you can also find "parameters".
$methods = array();
$parameters = array();
$curParameters = null;
for($i=0; $i < count($array); $i++) {
if(method_exists($this,$array[$i]) === TRUE) {
//associate last set of paremeters with method
if ($curParameters != null) {
$parameters[] = $curParameters;
}
//new method, new curParams
$methods[] = $i;
$curParameters = array();
} else {
//$array[$i] must be a parameter for the last method found
$curParameters[] = $array[$i];
}
}
//need to save the last set params founds
$parametres[] = $curParameters
When this is done parsing, you should have two arrays. The first array is $methods and the second is $parameters. These arrays should match up 1 to 1, meaning $parameters[x] should match up with $methods[x].
You could just turn
for($i=0; $i < count($array); $i++) {
if(method_exists($this,$array[$i]) === TRUE) {
$methods[] = $i;
}
}
To
$j = 0;
for($i=0; $i < count($array); $i++) {
if(method_exists($this,$array[$i]) === TRUE) {
$methods[] = $i;
$j++;
}
else {
$parameters[$j][] = $array[$i];
}
}
What you could do here is check if the value you are pulling out is in your methods array. If it is, then you know it is a method and not a parameter. if it isn't then you know it to be a parameter.
I would use the array_search() php method to accomplish this.
so you code would look something like:
for($x=0;$x<count($array);$x++)
{
if( array_search($array[$x], $methods) !== false)
{
//This is a Parameter
}
}
You can find more information here: http://php.net/manual/en/function.array-search.php
As I understand the question, you have an array of methods and parameters, and you want to separate these - presumably into separate arrays.
If so, you can try the following simplified example:
<?php
// example object with some public methods...
class Foo
{
function method1() {}
function method2() {}
function method3() {}
}
// list of methods and params
$array = [
'method1',
'param1',
'param2',
'method2',
'param3',
'method3',
'param4',
'param5',
];
// get a list of Foo's methods
$methods = get_class_methods('Foo');
// array_diff to get the params only
$params = array_diff($array, $methods);
print_r($params);
Yields:
Array
(
[1] => param1
[2] => param2
[4] => param3
[6] => param4
[7] => param5
)
YMMV - this example is outside the context of the object, so get_class_methods() can only see public methods. It can be used inside an object to get protected and private methods too. It depends on your exact use case.
Hope this helps.
It is more efficient to build $parameters array when building $methods array. But if for some unkown reasons, you want to keep your code as is, here is a way to do it:
$methods = array();
for($i=0; $i < count($array); $i++) {
if(method_exists($this,$array[$i]) === TRUE) {
$methods[] = $i;
}
}
if(count($methods) == 1) {
$parameters = array_slice($array,1,count($array));
} else {
$parameters = array();
for ($k=0; $k < (count($methods) - 1); $k++)
$parameters[$k] = array_slice($array,$methods[$k]+1,$methods[$k+1]-$methods[$k]-1);
$parameters[$k] = array_slice($array,$methods[$k]+1,count($methods)-$methods[$k]-1);
}
print_r($parameters);

PHP unset Not Working as expected

I am simply trying to remove all of the Array objects that have 'visible' set to '0'
Array:
{
"Count":5,
"0":{"id":"1","visible":"0"},
"1":{"id":"3","visible":"0"},
"2":{"id":"1","visible":"0"},
"3":{"id":"2","visible":"0"},
"4":{"id":"3","visible":"0"}
}
PHP:
function cleanup($arr) {
for($i = 0; $i < (count($arr)-1); $i++) {
if($arr[$i]['visible'] == false) {
unset($arr[$i]);
}
}
$newarr = array_unique($arr, SORT_REGULAR);
$newarr['Count'] = count($newarr)-1;
return $newarr;
}
Result:
{
"Count":2,
"3":{"id":"2","visible":"0"},
"4":{"id":"3","visible":"0"}
}
In my mind this should work and return {"Count":0}. Also Why have the 'keys' not been set to 0,1 instead of 3,4. Where am i going wrong?
You are using count($arr)-1) inside the for loop, and it gets re-evaluated every iteration, so after you unset the first three times, i is 3, but count($arr)-1) is 1, and you exit the loop.
You should set $j=count($arr)-1 before the for loop, and use for($i = 0; $i < $j; $i++)
In general it is bad programming practice (performance-wise) to use functions like count() inside the for loop
unset() will not reorder the array indexes if you removing an index from the middle of an numerical array. You need to reindex the array by yourself. array_values() is helpful here.
function cleanup($arr) {
for($i = 0; $i < (count($arr)-1); $i++) {
if($arr[$i]['visible'] == false) {
unset($arr[$i]);
}
}
$newarr = array_values(array_unique($arr, SORT_REGULAR));
return $newarr;
}
The Count property makes no sense for me therefore I dropped it away. You may use the function count() instead.

Most efficient way to search for object in an array by a specific property's value

What would be the fastest, most efficient way to implement a search method that will return an object with a qualifying id?
Sample object array:
$array = [
(object) ['id' => 'one', 'color' => 'white'],
(object) ['id' => 'two', 'color' => 'red'],
(object) ['id' => 'three', 'color' => 'blue']
];
What do I write inside of:
function findObjectById($id){
}
The desired result would return the object at $array[0] if I called:
$obj = findObjectById('one')
Otherwise, it would return false if I passed 'four' as the parameter.
You can iterate that objects:
function findObjectById($id){
$array = array( /* your array of objects */ );
foreach ( $array as $element ) {
if ( $id == $element->id ) {
return $element;
}
}
return false;
}
Edit:
Faster way is to have an array with keys equals to objects' ids (if unique);
Then you can build your function as follow:
function findObjectById($id){
$array = array( /* your array of objects with ids as keys */ );
if ( isset( $array[$id] ) ) {
return $array[$id];
}
return false;
}
It's an old question but for the canonical reference as it was missing in the pure form:
$obj = array_column($array, null, 'id')['one'] ?? false;
The false is per the questions requirement to return false. It represents the non-matching value, e.g. you can make it null for example as an alternative suggestion.
This works transparently since PHP 7.0. In case you (still) have an older version, there are user-space implementations of it that can be used as a drop-in replacement.
However array_column also means to copy a whole array. This might not be wanted.
Instead it could be used to index the array and then map over with array_flip:
$index = array_column($array, 'id');
$map = array_flip($index);
$obj = $array[$map['one'] ?? null] ?? false;
On the index the search problem might still be the same, the map just offers the index in the original array so there is a reference system.
Keep in mind thought that this might not be necessary as PHP has copy-on-write. So there might be less duplication as intentionally thought. So this is to show some options.
Another option is to go through the whole array and unless the object is already found, check for a match. One way to do this is with array_reduce:
$obj = array_reduce($array, static function ($carry, $item) {
return $carry === false && $item->id === 'one' ? $item : $carry;
}, false);
This variant again is with the returning false requirement for no-match.
It is a bit more straight forward with null:
$obj = array_reduce($array, static function ($carry, $item) {
return $carry ?? ($item->id === 'one' ? $item : $carry);
}, null);
And a different no-match requirement can then be added with $obj = ...) ?? false; for example.
Fully exposing to foreach within a function of its own even has the benefit to directly exit on match:
$result = null;
foreach ($array as $object) {
if ($object->id === 'one') {
$result = $object;
break;
}
}
unset($object);
$obj = $result ?? false;
This is effectively the original answer by hsz, which shows how universally it can be applied.
You can use the function array_search of php like this
$key=array_search("one", array_column(json_decode(json_encode($array),TRUE), 'color'));
var_dump($array[$key]);
i: is the index of item in array
1: is the property value looking for
$arr: Array looking inside
'ID': the property key
$i = array_search(1, array_column($arr, 'ID'));
$element = ($i !== false ? $arr[$i] : null);
Well, you would would have to loop through them and check compare the ID's unless your array is sorted (by ID) in which case you can implement a searching algorithm like binary search or something of that sort to make it quicker.
My suggestion would be to first sort the arrays using a sorting algorithm (binary sort, insertion sort or quick sort) if the array is not sorted already. Then you can implement a search algorithm which should improve performance and I think that's as good as it gets.
http://www.algolist.net/Algorithms/Binary_search
This is my absolute favorite algorithm for very quickly finding what I need in a very large array, quickly. It is a Binary Search Algorithm implementation I created and use extensively in my PHP code. It hands-down beats straight-forward iterative search routines. You can vary it a multitude of ways to fit your need, but the basic algorithm remains the same.
To use it (this variation), the array must be sorted, by the index you want to find, in lowest-to-highest order.
function quick_find(&$array, $property, $value_to_find, &$first_index) {
$l = 0;
$r = count($array) - 1;
$m = 0;
while ($l <= $r) {
$m = floor(($l + $r) / 2);
if ($array[$m]->{$property} < $value_to_find) {
$l = $m + 1;
} else if ($array[$m]->{$property} > $value_to_find) {
$r = $m - 1;
} else {
$first_index = $m;
return $array[$m];
}
}
return FALSE;
}
And to test it out:
/* Define a class to put into our array of objects */
class test_object {
public $index;
public $whatever_you_want;
public function __construct( $index_to_assign ) {
$this->index = $index_to_assign;
$this->whatever_you_want = rand(1, 10000000);
}
}
/* Initialize an empty array we will fill with our objects */
$my_array = array();
/* Get a random starting index to simulate data (possibly loaded from a database) */
$my_index = rand(1256, 30000);
/* Say we are needing to locate the record with this index */
$index_to_locate = $my_index + rand(200, 30234);
/*
* Fill "$my_array()" with ONE MILLION objects of type "test_object"
*
* 1,000,000 objects may take a little bit to generate. If you don't
* feel patient, you may lower the number!
*
*/
for ($i = 0; $i < 1000000; $i++) {
$searchable_object = new test_object($my_index); // Create the object
array_push($my_array, $searchable_object); // Add it to the "$my_array" array
$my_index++; /* Increment our unique index */
}
echo "Searching array of ".count($my_array)." objects for index: " . $index_to_locate ."\n\n";
$index_found = -1; // Variable into which the array-index at which our object was found will be placed upon return of the function.
$object = quick_find($my_array, "index", $index_to_locate, $index_found);
if ($object == NULL) {
echo "Index $index_to_locate was not contained in the array.\n";
} else {
echo "Object found at index $index_found!\n";
print_r($object);
}
echo "\n\n";
Now, a few notes:
You MAY use this to find non-unique indexes; the array MUST still be sorted in ascending order. Then, when it finds an element matching your criteria, you must walk the array backwards to find the first element, or forward to find the last. It will add a few "hops" to your search, but it will still most likely be faster than iterating a large array.
For STRING indexes, you can change the arithmetic comparisons (i.e. " > " and " < " ) in quick_find() to PHP's function "strcasecmp()". Just make sure the STRING indexes are sorted the same way (for the example implementation): Alphabetically and Ascending.
And if you want to have a version that can search arrays of objects sorted in EITHER ascending OR decending order:
function quick_find_a(&$array, $property, $value_to_find, &$first_index) {
$l = 0;
$r = count($array) - 1;
$m = 0;
while ($l <= $r) {
$m = floor(($l + $r) / 2);
if ($array[$m]->{$property} < $value_to_find) {
$l = $m + 1;
} else if ($array[$m]->{$property} > $value_to_find) {
$r = $m - 1;
} else {
$first_index = $m;
return $array[$m];
}
}
return FALSE;
}
function quick_find_d(&$array, $property, $value_to_find, &$first_index) {
$l = 0;
$r = count($array) - 1;
$m = 0;
while ($l <= $r) {
$m = floor(($l + $r) / 2);
if ($value_to_find > $array[$m]->{$property}) {
$r = $m - 1;
} else if ($value_to_find < $array[$m]->{$property}) {
$l = $m + 1;
} else {
$first_index = $m;
return $array[$m];
}
}
return FALSE;
}
function quick_find(&$array, $property, $value_to_find, &$first_index) {
if ($array[0]->{$property} < $array[count($array)-1]->{$property}) {
return quick_find_a($array, $property, $value_to_find, $first_index);
} else {
return quick_find_d($array, $property, $value_to_find, $first_index);
}
}
The thing with performance of data structures is not only how to get but mostly how to store my data.
If you are free to design your array, use an associative array:
$array['one']->id = 'one';
$array['one']->color = 'white';
$array['two']->id = 'two';
$array['two']->color = 'red';
$array['three']->id = 'three';
$array['three']->color = 'blue';
Finding is then the most cheap: $one = $array['one];
UPDATE:
If you cannot modify your array constitution, you could create a separate array which maps ids to indexes. Finding an object this way does not cost any time:
$map['one'] = 0;
$map['two'] = 1;
$map['three'] = 2;
...
getObjectById() then first lookups the index of the id within the original array and secondly returns the right object:
$index = $map[$id];
return $array[$index];
Something I like to do in these situations is to create a referential array, thus avoiding having to re-copy the object but having the power to use the reference to it like the object itself.
$array['one']->id = 'one';
$array['one']->color = 'white';
$array['two']->id = 'two';
$array['two']->color = 'red';
$array['three']->id = 'three';
$array['three']->color = 'blue';
Then we can create a simple referential array:
$ref = array();
foreach ( $array as $row )
$ref[$row->id] = &$array[$row->id];
Now we can simply test if an instance exists in the array and even use it like the original object if we wanted:
if ( isset( $ref['one'] ) )
echo $ref['one']->color;
would output:
white
If the id in question did not exist, the isset() would return false, so there's no need to iterate the original object over and over looking for a value...we just use PHP's isset() function and avoid using a separate function altogether.
Please note when using references that you want use the "&" with the original array and not the iterator, so using &$row would not give you what you want.
This is definitely not efficient, O(N). But it looks sexy:
$result = array_reduce($array, function ($found, $obj) use ($id) {
return $obj['id'] == $id ? $obj : $found;
}, null);
addendum:
I see hakre already posted something akin to this.
Here is what I use. Reusable functions that loop through an array of objects. The second one allows you to retrieve a single object directly out of all matches (the first one to match criteria).
function get_objects_where($match, $objects) {
if ($match == '' || !is_array($match)) return array ();
$wanted_objects = array ();
foreach ($objects as $object) {
$wanted = false;
foreach ($match as $k => $v) {
if (is_object($object) && isset($object->$k) && $object->$k == $v) {
$wanted = true;
} else {
$wanted = false;
break;
};
};
if ($wanted) $wanted_objects[] = $object;
};
return $wanted_objects;
};
function get_object_where($match, $objects) {
if ($match == '' || !is_array($match)) return (object) array ();
$wanted_objects = get_objects_where($match, $objects);
return count($wanted_objects) > 0 ? $wanted_objects[0] : (object) array ();
};
The easiest way:
function objectToArray($obj) {
return json_decode(json_encode($obj), true);
}

Is there a php function like python's zip?

Python has a nice zip() function. Is there a PHP equivalent?
As long as all the arrays are the same length, you can use array_map with null as the first argument.
array_map(null, $a, $b, $c, ...);
If some of the arrays are shorter, they will be padded with nulls to the length of the longest, unlike python where the returned result is the length of the shortest array.
array_combine comes close.
Otherwise nothing like coding it yourself:
function array_zip($a1, $a2) {
for($i = 0; $i < min(length($a1), length($a2)); $i++) {
$out[$i] = [$a1[$i], $a2[$i]];
}
return $out;
}
Try this function to create an array of arrays similar to Python’s zip:
function zip() {
$args = func_get_args();
$zipped = array();
$n = count($args);
for ($i=0; $i<$n; ++$i) {
reset($args[$i]);
}
while ($n) {
$tmp = array();
for ($i=0; $i<$n; ++$i) {
if (key($args[$i]) === null) {
break 2;
}
$tmp[] = current($args[$i]);
next($args[$i]);
}
$zipped[] = $tmp;
}
return $zipped;
}
You can pass this function as many array as you want with as many items as you want.
This works exactly as Python's zip() function, and is compatible also with PHP < 5.3:
function zip() {
$params = func_get_args();
if (count($params) === 1){ // this case could be probably cleaner
// single iterable passed
$result = array();
foreach ($params[0] as $item){
$result[] = array($item);
};
return $result;
};
$result = call_user_func_array('array_map',array_merge(array(null),$params));
$length = min(array_map('count', $params));
return array_slice($result, 0, $length);
};
It merges the arrays in the manner Python's zip() does and does not return elements found after reaching the end of the shortest array.
The following:
zip(array(1,2,3,4,5),array('a','b'));
gives the following result:
array(array(1,'a'), array(2,'b'))
and the following:
zip(array(1,2,3,4,5),array('a','b'),array('x','y','z'));
gives the following result:
array(array(1,'a','x'), array(2,'b','y'))
Check this demonstration for a proof of the above.
EDIT: Added support for receiving single argument (array_map behaves differently in that case; thanks Josiah).
Solution
The solution matching zip() very closely, and using builtin PHP functions at the same time, is:
array_slice(
array_map(null, $a, $b, $c), // zips values
0, // begins selection before first element
min(array_map('count', array($a, $b, $c))) // ends after shortest ends
);
Why not simple array_map(null, $a, $b, $c) call?
As I already mentioned in my comment, I tend to favor nabnabit's solution (array_map(null, $a, $b, ...)), but in a slightly modified way (shown above).
In general this:
array_map(null, $a, $b, $c);
is counterpart for Python's:
itertools.izip_longest(a, b, c, fillvalue=None)
(wrap it in list() if you want list instead of iterator). Because of this, it does not exactly fit the requirement to mimic zip()'s behaviour (unless all the arrays have the same length).
You can find zip as well as other Python functions in Non-standard PHP library. Including operator module and defaultarray.
use function nspl\a\zip;
$pairs = zip([1, 2, 3], ['a', 'b', 'c']);
I wrote a zip() functions for my PHP implementation of enum.
The code has been modified to allow for a Python-style zip() as well as Ruby-style. The difference is explained in the comments:
/*
* This is a Python/Ruby style zip()
*
* zip(array $a1, array $a2, ... array $an, [bool $python=true])
*
* The last argument is an optional bool that determines the how the function
* handles when the array arguments are different in length
*
* By default, it does it the Python way, that is, the returned array will
* be truncated to the length of the shortest argument
*
* If set to FALSE, it does it the Ruby way, and NULL values are used to
* fill the undefined entries
*
*/
function zip() {
$args = func_get_args();
$ruby = array_pop($args);
if (is_array($ruby))
$args[] = $ruby;
$counts = array_map('count', $args);
$count = ($ruby) ? min($counts) : max($counts);
$zipped = array();
for ($i = 0; $i < $count; $i++) {
for ($j = 0; $j < count($args); $j++) {
$val = (isset($args[$j][$i])) ? $args[$j][$i] : null;
$zipped[$i][$j] = $val;
}
}
return $zipped;
}
Example:
$pythonzip = zip(array(1,2,3), array(4,5), array(6,7,8));
$rubyzip = zip(array(1,2,3), array(4,5), array(6,7,8), false);
echo '<pre>';
print_r($pythonzip);
print_r($rubyzip);
echo '<pre>';
// create
$a = array("a", "c", "e", "g", "h", "i");
$b = array("b", "d", "f");
$zip_array = array();
// get length of the longest array
$count = count(max($a, $b));
// zip arrays
for($n=0;$n<$count;$n++){
if (array_key_exists($n,$a)){
$zip_array[] = $a[$n];
}
if (array_key_exists($n,$b)){
$zip_array[] = $b[$n];
}
}
// test result
echo '<pre>'; print_r($zip_array); echo '<pre>';
function zip() {
$zip = [];
$arrays = func_get_args();
if ($arrays) {
$count = min(array_map('count', $arrays));
for ($i = 0; $i < $count; $i++) {
foreach ($arrays as $array) {
$zip[$i][] = $array[$i];
}
}
}
return $zip;
}
This works like in Python
function zip(...$arrays) {
return array_filter(
array_map(null, ...(count($arrays) > 1 ? $arrays : array_merge($arrays, [[]]))),
fn($z) => count($z) === count(array_filter($z)) || count($arrays) === 1
);
}
/**
* Takes an arbitrary number of arrays and "zips" them together into a single
* array, taking one value from each array and putting them into a sub-array,
* before moving onto the next.
*
* If arrays are uneven lengths, will stop at the length of the shortest array.
*/
function array_zip(...$arrays) {
$result = [];
$args = array_map('array_values',$arrays);
$min = min(array_map('count',$args));
for($i=0; $i<$min; ++$i) {
$result[$i] = [];
foreach($args as $j=>$arr) {
$result[$i][$j] = $arr[$i];
}
}
return $result;
}
Usage:
print_r(array_zip(['a','b','c'],[1,2,3],['x','y']));
Output:
Array
(
[0] => Array
(
[0] => a
[1] => 1
[2] => x
)
[1] => Array
(
[0] => b
[1] => 2
[2] => y
)
)
To overcome the issues with passing a single array to map_array, you can pass this function...unfortunately you can't pass "array" as it's not a real function but a builtin thingy.
function make_array() { return func_get_args(); }
Dedicated to those that feel like it should be related to array_combine:
function array_zip($a, $b)
{
$b = array_combine(
$a,
$b
);
$a = array_combine(
$a,
$a
);
return array_values(array_merge_recursive($a,$b));
}
you can see array_map method:
$arr1 = ['get', 'method'];
$arr2 = ['post'];
$ret = array_map(null, $arr1, $arr2);
output:
[['get', 'method'], ['post', null]]
php function.array-map

Categories