More of a curiosity question. If you have an array of arrays, is there any shorthand for iterating over the interior arrays? You can obviously use the following to do it, but I wondered if there's a single line call that gets rid of the second foreach.
$arr = array(array(1,2,3), array(4,5,6), array(7,8,9));
foreach($arr as $interiorArr)
{
foreach($interiorArr as $number)
{
echo $number;
}
}
output would be "123456789"
Depending on what you're needing to do, you can recursively walk the array:
array_walk_recursive($arr, function($v) { echo $v; });
For this simple example (echo and print aren't functions so can't be used as a callback):
array_walk_recursive($arr, 'printf');
Again, depending on what you're needing to do, and for this simple example, you can foreach and use a variety of functions that operates on arrays:
foreach($arr as $interiorArr)
{
echo implode($interiorArr);
}
Related
Having read this SO post, In PHP I am aware that you can get the index under iteration with array_map as such:
array_map(function($item, $index) { ... }, $items, array_keys($items));
How can I get the an $index available to me when I use array_reduce? I have tried:
array_reduce($items, array_keys($items), function($acc, $item, $index) { ... }, array());
array_reduce($items, function($acc, $item, $index) { ... }, array(), array_keys($items));
But I still can't seem to get $index in an array_reduce. Has anyone successfully done this before?
EDIT
Here's some context as to why I am asking this question.
I do not want to use foreach because I would have to mutate an array outside of the foreach in order to create my collection. I would prefer to avoid mutation.
Other languages allow one to use reduce and get access to the current index like in JavaScript and Ruby. I was hoping to get the same feature in PHP. Oh well! Looks like I'm going to have to use a foreach to create my array while also having the current index under iteration.
I just had same issue. It's pretty simple to solve.
$i = 0;
$p = array_reduce($array, function($output, $item) use (&$i) {
// use $i
// do something with $item and/or $output
$i++; // increment $i
return $output;
}, $initial);
&$i pass $i as reference and grants it will be updated.
<?php
$data = ['one', 'two', 'three'];
$result = array_reduce($data, function($carry, $item){
$carry['out'] .= $carry['i'] . ') '. $item . '; ';
$carry['i']++;
return $carry;
}, ['out' => '', 'i' => 1] )['out'];
echo $result; // 1) one; 2) two; 3) three;
Arrays in PHP are peculiar things: they can be used as lists, queues, dictionaries, sets, ordered dictionaries, and all sorts of other multi-valued structures. However, most functions are written with one or two of those structures in mind.
In the case of array_reduce, the array is treated as a list - an ordered collection of items. As such, the keys of the array are not handed to the callback. This makes sense for common cases, like calculating a total, or an average, etc.
There are undoubtedly cases where you want to instead reduce an ordered dictionary of key-value pairs; unfortunately, PHP does not provide a function for that.
On the other hand, there are two related functions which might be usable instead:
array_map, which runs the callback on each element and produces a new array with one item of output for item of input
array_walk, which runs the callback on each element and ignores the result, but which can take a third parameter by reference where side-effects can be accumulated
All three functions can also trivially be implemented with a foreach loop, so you could write your own reduce function something like this (untested):
function array_reduce_assoc(array $array, callable $callback, $initial=null) {
$carry = $initial;
foreach ( $array as $key => $value ) {
$carry = $callback($carry, $key, $value);
}
return $carry;
}
You already know you how to get the index in array_map, so you could use that to reduce instead if you like. Just use a reference to the "carry" variable in the callback.
$example = ['a' => 1, 'b' => 2, 'c' => 3];
array_map(function($key, $value) use (&$reduced) {
$reduced .= "$key$value"; // for example
}, array_keys($example), $example);
echo $reduced; //a1b2c3
I'm not sure I see the advantage of this over foreach, but it's another possible way to do it.
What you're aware about the getting index in array_reduce doesn't exist. Check documentation.
The question is why?
Look, reduce is being used for the purpose of getting down to one single value, it's aggregation. You have initial value, and next value, show your reduce strategy. There is no point in knowing current item index.
In some other languages, they might provide current index, but not for this array_reduce in PHP. It's language and function designed, there are some constraints in implementation.
But it doesn't mean you can't have it. You can have it, but not through callback!
$i = 0;
$data = [1, 2, 3, 4];
// (1)
$result = array_reduce($data, function ($c, $i) { return $c + $i; }, 0);
// (2)
array_reduce($data, function ($c, $i) { echo "$i\n"; $i++; return $c + $i; }, 0);
The thing is, the function is designed to do this. Or you're trying to use a wrong function. Some other functions might be what you're looking for.
Or you can write a function that do it, too :)
This is similar to another answer, but differs on a couple of points.
First, the other answer provides an example, but not a complete one. Also the
other answer defines the callback arguments as $carry, $key, $value. I feel
that $carry, $value, $key would be better, as it would match
JavaScript reduce.
It would also keep the order of PHP’s own array_reduce, while just adding
an extra argument. For my example I am implementing array_flip, just to
demonstrate what is possible:
<?php
$a = ['May', 'June'];
$m = [];
$f = function ($m_acc, $s_cur, $n_idx) {
return $m_acc + [$s_cur => $n_idx];
};
foreach ($a as $n => $s) {
$m = $f($m, $s, $n);
}
print_r($m);
I'm trying to find a simpler way to create new arrays from existing arrays and values. There are two routines I'd like to optimize that are similar in construction. The form of the first one is:
$i = 0;
$new_array = array();
foreach ($my_array as $value) {
$new_array[$i][0] = $constant; // defined previously and unchanging
$new_array[$i][1] = $value; // different for each index of $my_array
$i++;
}
The form of the second one has not one but two different values per constant; notice that $value comes before $key in the indexing:
$i = 0;
$new_array = array();
foreach ($my_array as $key => $value) {
$new_array[$i][0] = $constant; // defined previously and unchanging
$new_array[$i][1] = $value; // different for each index of $my_array
$new_array[$i][2] = $key; // different for each index of $my_array
$i++;
}
Is there a way to optimize these procedures with shorter and more efficient routines using the array operators of PHP? (There are many, of course, and I can't find one that seems to fit the bill.)
I believe a combination of Wouter Thielen's suggestions regarding the other solutions actually holds the best answer for me.
For the first case I provided:
$new_array = array();
// $my_array is numeric, so $key will be index count:
foreach ($my_array as $key => $value) {
$new_array[$key] = array($constant, $value);
};
For the second case I provided:
// $my_array is associative, so $key will initially be a text index (or similar):
$new_array = array();
foreach ($my_array as $key => $value) {
$new_array[$key] = array($constant, $value, $key);
};
// This converts the indexes to consecutive integers starting with 0:
$new_array = array_values($new_array);
it is shorter, when you use the array-key instead of the $i-counter
$new_array = array();
foreach ($my_array as $key => $value) {
$new_array[$key][0] = $constant; // defined previously and unchanging
$new_array[$key][1] = $value; // different for each index of $my_array
}
Use array_map:
$new_array = array_map(function($v) use ($constant) {
return array($constant, $v);
}, $my_array);
If you want to use the keys too, for your second case:
$new_array = array_map(function($k, $v) use ($constant) {
return array($constant, $v, $k);
}, array_keys($my_array), $my_array);
Assuming the $constant variable is defined in the caller's scope, you'll need to use use ($constant) to pass it into the function's scope.
array_walk is similar, but modifies the array you pass to it, so if you want to update $my_array itself, use array_walk. Your second case then becomes this:
array_walk($my_array, function(&$val, $key) use($constant) {
$val = array($constant, $val, $key);
});
In both examples above for the second case, you'll end up with an associative array (i.e. with the keys still being the keys for the array). If you want to convert this into a numerically indexed array, use array_values:
$numerically_indexed = array_values($associative);
I asked a question similar to this a few days ago, check it out:
PHP - Fastest way to convert a 2d array into a 3d array that is grouped by a specific value
I think that you have an optimal way when it comes to dealing with large amount of data. For smaller amounts there is a better way as was suggested by the benchmarks in my question.
I think too that readability and understanding the code can also be an issue here and I find that things that you can understand are worth more later on than ideas that you do not really grasp as it generally takes a long time to understand them again as it can be quite confusing while debugging issues.
I would suggest, you take a look at the differences between JSON encoded arrays and serialised arrays as there can be major performance differences when working with the two. It seems that as it is now JSON encoded arrays are a more optimised format (faster) for holding and working with data however this will likely change with PHP 7. It would be useful to note that they are also more portable.
Further Reading:
Preferred method to store PHP arrays (json_encode vs serialize)
http://techblog.procurios.nl/k/n618/news/view/34972/14863/cache-a-large-array-json-serialize-or-var_export.html
this is the output of my array
[["1"],["1"],["1"],["1"],["1"],["1"],["1"],["1"],["1"],["1"],["1"],["1"],["1"],["1"]]
but I would like this to look like
[1,1,1,1,1,1,1]
how would this be achieved in php, it seems everything I do gets put into an object in the array, when I don't want that. I tried using array_values and it succeeded in returning the values only, since I did have keys originally, but this is still not the completely desired outcome
$yourArray = [["1"],["1"],["1"],["1"],["1"],["1"],["1"],["1"],["1"],["1"],["1"],["1"],["1"],["1"]];
use following code in PHP 5.3+
$newArray = array_map(function($v) {
return (int)$v[0];
}, $yourArray);
OR use following code in other PHP version
function covertArray($v) {
return (int)$v[0];
}
$newArray = array_map('covertArray', $yourArray)
You could always do a simple loop...
$newArray = array();
// Assuming $myArray contains your multidimensional array
foreach($myArray as $value)
{
$newArray[] = $value[0];
}
You could beef it up a little and avoid bad indexes by doing:
if( isset($value[0]) ) {
$newArray[] = $value[0];
}
Or just use one of the many array functions to get the value such as array_pop(), array_slice(), end(), etc.
This would be easy to do with regular array with a simple for statement. EG:
$b= array('A','B','C');
$s=sizeof($b);
for ($i=0; $i <$s ; $i++) $b[$i]='your_face';
print_r($b);
But if I use assoc array, I can't seem any easy way to do it. I could, of course use a foreach loop, but it is actually replicating the $value variables instead of returning a pointer to an actual array entity. EG, this will not work:
$b= array('A'=>'A','B'=>'B','C'=>'C');
foreach ($b as $v) $v='your_face';
print_r($b);
Of course we could have some stupid idea like this:
$b= array('A'=>'A','B'=>'B','C'=>'C');
foreach ($b as $k => $v) $b[$k]='your_face';
print_r($b);
But this would be an awkward solution, because it would redundantly recreate $v variables which are never used.
So, what's a better way to loop through an assoc?
You could try:
foreach(array_keys($b) as $k) {
$b[$k] = 'your_face';
}
print_r($b);
See the following link for an explaination of array_keys: http://php.net/manual/en/function.array-keys.php
Not sure if that's what you want, but here goes:
foreach(array_keys($b) as $k) $b[$k] = 'your_face';
suppose I have an array of names, what I want is that I want to search this particular array against the string or regular expression and then store the found matches in another array. Is this possible ? if yes then please can your give me hint ? I am new to programming.
To offer yet another solution, I would recommend using PHP's internal array_filter to perform the search.
function applyFilter($element){
// test the element and see if it's a match to
// what you're looking for
}
$matches = array_filter($myArray,'applyFilter');
As of PHP 5.3, you can use an anonymous function (same code as above, just declared differently):
$matches = array_filter($myArray, function($element) {
// test the element and see if it's a match to
// what you're looking for
});
what you would need to di is map the array with a callback like so:
array_filter($myarray,"CheckMatches");
function CheckMatches($key,$val)
{
if(preg_match("...",$val,$match))
{
return $match[2];
}
}
This will run the callback for every element in the array!
Updated to array_filter
well in this case you would probably do something along the lines of a foreach loop to iterate through the array to find what you are looking for.
foreach ($array as $value) {
if ($searching_for === $value) {/* You've found what you were looking for, good job! */}
}
If you wish to use a PHP built in method, you can use in_array
$array = array("1", "2", "3");
if (in_array("2", $array)) echo 'Found ya!';
1) Store the strings in array1
2) array2 against you want to match
3) array3 in which you store the matches
$array1 = array("1","6","3");
$array2 = array("1","2","3","4","5","6","7");
foreach($array1 as $key=>$value){
if(in_array($value,$array2))
$array3[] = $value;
}
echo '<pre>';
print_r($array3);
echo '</pre>';