PHP Need to recursively reverse an array - php

I need to recursively reverse a HUGE array that has many levels of sub arrays, and I need to preserve all of the keys (which some are int keys, and some are string keys), can someone please help me? Perhaps an example using array_reverse somehow? Also, is using array_reverse the only/best method of doing this?
Thanks :)

Try this:
function array_reverse_recursive($arr) {
foreach ($arr as $key => $val) {
if (is_array($val))
$arr[$key] = array_reverse_recursive($val);
}
return array_reverse($arr);
}

Recursively:
<?php
$a = array(1,3,5,7,9);
print_r($a);
function rev($a) {
if (count($a) == 1)
return $a;
return array_merge(rev(array_slice($a, 1, count($a) - 1)), array_slice($a, 0, 1));
}
$a = rev($a);
print_r($a);
?>
output:
Array
(
[0] => 1
[1] => 3
[2] => 5
[3] => 7
[4] => 9
)
Array
(
[0] => 9
[1] => 7
[2] => 5
[3] => 3
[4] => 1
)

Reversing a HUGE php array in situ (but not recursively):
function arrayReverse(&$arr){
if (!is_array($arr) || empty($arr)) {
return;
}
$rev = array();
while ( false !== ( $val = end($arr) ) ){
$rev[ key($arr) ] = $val;
unset( $arr[ key($arr) ] );
}
$arr = $rev;
}
//usage
$test = array(5, 'c'=>100, 10, 15, 20);
arrayReverse($test);
var_export($test);
// result: array ( 3 => 20, 2 => 15, 1 => 10, 'c' => 100, 0 => 5, )

Related

Delete the indexes of elements which exists more than once in an array php

I have the following array,
Array
(
[0] => 5600
[1] => 5600
[2] => 5500
[3] => 5500
[4] => 5003
[5] => 5002
[6] => 5001
[7] => 768
[8] => 768
[9] => 767
[10] => 730
[11] => 666
[12] => 575
)
Now I want to delete the indexes of elements which exists more than once in an array. For example I want the above given array like this.
Array
(
[0] => 5003
[1] => 5002
[2] => 5001
[3] => 767
[4] => 730
[5] => 666
[6] => 575
)
Share your ideas if any one has the key.
<?php
// sample input
$arr = array(1,1,2,2,2,3,4,5);
// input
print_r($arr);
// to retain keys
print_r(
array_diff($arr, array_diff_assoc($arr, array_unique($arr)))
);
// to reset keys using array_values
print_r(
array_values(
array_diff($arr, array_diff_assoc($arr, array_unique($arr)))
)
);
?>
Test results
akshay#db-3325:/tmp$ php test.php
Array
(
[0] => 1
[1] => 1
[2] => 2
[3] => 2
[4] => 2
[5] => 3
[6] => 4
[7] => 5
)
Array
(
[5] => 3
[6] => 4
[7] => 5
)
Array
(
[0] => 3
[1] => 4
[2] => 5
)
Eliminate repeating values with array_unique, restore indexes with array_values:
print_r(array_values(array_unique($arr)));
Update:
$new = [];
foreach (array_count_values($arr) as $k => $v) {
if ($v == 1) {
$new[] = $k;
}
}
As a oneliner with array_filter (since php5.6):
$new = array_filter(
array_count_values($arr), function($v, $k) {
return $v == 1;
},
ARRAY_FILTER_USE_BOTH
);
Thank you for the question. Mine is not a nice solution. I used your question to make a little exercise of test driven development.
use PHPUnit\Framework\TestCase;
final class RemoveNonUniqueItemsTest extends TestCase
{
public function testEmptyArrayReturnEmptyArray()
{
$uniqueItems = Remover::keepOnlyUnique([]);
$this->assertEquals(
[],
$uniqueItems->asArray()
);
}
public function testArrayWithUniqueKeysReturnSameArray()
{
$uniqueItems = Remover::keepOnlyUnique([1,2,3]);
$this->assertEquals(
[1,2,3],
$uniqueItems->asArray()
);
}
public function testCountNumnerOfItemsAValueAppears()
{
$uniqueItems = Remover::keepOnlyUnique([1,2,3,3]);
$this->assertEquals(
2,
$uniqueItems->items(3)
);
}
public function testRemoveValuesThatExistsTwice()
{
$uniqueItems = Remover::keepOnlyUnique([1,2,3,3]);
$this->assertEquals(
[1,2],
$uniqueItems->asArray()
);
}
}
final class Remover
{
private $items;
private function __construct(array $items)
{
$this->items = $items;
}
public static function keepOnlyUnique(array $items) : Remover
{
return new self($items);
}
public function asArray() : array
{
$newArray = [];
foreach ($this->items as $itemKey => $itemValue) {
if ($this->items($itemValue) == 1) {
$newArray[] = $itemValue;
}
}
return $newArray;
}
public function items(int $value) : int
{
$count = 0;
foreach ($this->items as $itemKey => $itemValue) {
if ($itemValue == $value) {
$count++;
}
}
return $count;
}
}
Using simple loops.
Count how many times each value occurs. And then loop through these frequencies. If the value only occurs once add to our desired array.
<?php
function only_unique(array $values) {
$result = $freq = array();
foreach($values as $value)
isset($freq[$value]) ? $freq[$value]++ : $freq[$value] = 1;
foreach($freq as $key => $value)
if($value == 1)
$result[] = $key;
return $result;
}
$nums = [1,2,2,3,3,3,4];
var_dump(only_unique($nums));
Output:
array(2) {
[0]=>
int(1)
[1]=>
int(4)
}
The above is similar to below:
$desired =
array_keys(
array_filter(
array_count_values($nums), function($v) {
return $v == 1;
}
)
);
Almost every Answer offered here is right.... but then, again... here's another one:
<?php
$arr = [
5600, 5600, 5500, 5500, 5003, 5002,
5001, 768, 768, 767, 730, 666, 575,
];
function arraySansDuplicates($array){
$result = [];
foreach($array as $value){
if(!in_array($value, $result)){
$result[] = $value;
}else{
$key = array_search($value, $result);
unset($result[$key]);
}
}
return array_values($result);
}
var_dump( arraySansDuplicates($arr) );

Find combination of array keys with values

In order to optimize the output I recently ran into a situation where I have to get the all the combinations of array keys inside an array. I looked into several places (including StackOverflow) but could not find the solution since most are related to permutation rather than combination.
Given this input
$input = ['jack' => 11, 'moe' => 12, 'shane' => 12];
Output should be something like this (the order inside an array does not matter).
$output = [
['jack' => 11],
['jack' => 11, 'moe' => 12]
['jack' => 11, 'moe' => 12, 'shane' => 12]
['moe' => 12],
['moe' => 12, 'shane' => 12]
['shane' => 12],
['shane' => 12, 'jack' => 11]
];
I tried this but after third iteration it does not work.
function combination(array $inputs, array $temp, &$collect) {
if (!empty($temp)) {
$collect[] = $temp;
}
for ($i = 0; $i < sizeof($inputs); $i++) {
$inputCopy = $inputs;
$elem = array_splice($inputCopy, $i, 1);
if (count($inputCopy) > 0) {
$temp[array_keys($elem)[0]] = array_values($elem)[0];
combination($inputCopy, $temp, $collect);
} else {
$temp[array_keys($elem)[0]] = array_values($elem)[0];
$collect[] = $temp;
$temp = [];
}
$i++;
}
}
Though I need this in PHP even Python (without using itertools combination), Java, Javascript will work for me.
I have found a way of doing what you want, but definitely, this is not a "fancy" solution. I would suggest you to work a little bit with it to find something better, but at least this gives you the result.
Here you go :
<?php
$baseArray = [
"joe" => 11,
"molly" => 12,
"sam" => 13,
];
function getAllPermutations($array = []) {
if (empty($array)) {
return [];
}
$result = [];
foreach ($array as $key => $value) {
unset($array[$key]);
$subPermutations = getAllPermutations($array);
$result[] = [$key => $value];
foreach ($subPermutations as $sub) {
$result[] = array_merge([$key => $value] , $sub);
}
}
return $result;
}
print_r(getAllPermutations($baseArray));
Output being :
Array
(
[0] => Array
(
[joe] => 11
)
[1] => Array
(
[joe] => 11
[molly] => 12
)
[2] => Array
(
[joe] => 11
[molly] => 12
[sam] => 13
)
[3] => Array
(
[joe] => 11
[sam] => 13
)
[4] => Array
(
[molly] => 12
)
[5] => Array
(
[molly] => 12
[sam] => 13
)
[6] => Array
(
[sam] => 13
)
) }
Hope this helped.
You read about really clever non-recursive algorithm here: PHP: Find every combination of an Array. You can adopt it (mostly copy and paste) to write generator function:
function keyCombinations($array)
{
$keys = array_keys($array);
$num = count($keys);
$total = pow(2, $num);
for ($i = 1; $i < $total; $i++) {
$combination = [];
for ($j = 0; $j < $num; $j++) {
if (pow(2, $j) & $i) {
$key = $keys[$j];
$combination[$key] = $array[$key];
}
}
yield $combination;
}
}
One important point here. In the original article $i initialized with 0, we initialize it with 1 to exclude empty array from the result.
Having this function you can get all combinations:
foreach (keyCombinations($input) as $combination) {
print_r($combination);
}
Here is working demo.
If, in your final combination, you include the empty set, your problem is equivalent to enumerating a binary number of "n" bits. Where "n" is the number of elements in your set.
You need a recursive algorithm like this one:
def comb(initialSet, results=[], currentIndex=0, currentResult=[]):
if currentIndex >= len(initialSet):
results.append( currentResult[:] )
else:
currentResult.append( initialSet[currentIndex] )
comb(initialSet, results, currentIndex + 1, currentResult)
currentResult.pop()
comb(initialSet, results, currentIndex + 1, currentResult)
return results

Extract negative and non-negative values from an array

I need to divide an array into two arrays.
One array will contain all positive values (and zeros), the other all negative values.
Example array:
$ts = [7,-10,13,8,0,4,-7.2,-12,-3.7,3.5,-9.6,6.5,-1.7,-6.2,7];
Negatives result array:
[-10,-7.2,-12,-3.7,-9.6,-1.7,-6.2];
Non-negatives result array:
[7,13,8,0,4,3.5,6.5,7];
Without using any array functions..
Pretty straightforward. Just loop through the array and check if the number is less than 0, if so , push it in the negative array else push it in the positive array.
<?php
$ts=array(7,-10,13,8,4,-7.2,-12,-3.7,3.5,-9.6,6.5,-1.7,-6.2,7);
$pos_arr=array(); $neg_arr=array();
foreach($ts as $val)
{
($val<0) ? $neg_arr[]=$val : $pos_arr[]=$val;
}
print_r($pos_arr);
print_r($neg_arr);
OUTPUT :
Array
(
[0] => 7
[1] => 13
[2] => 8
[3] => 4
[4] => 3.5
[5] => 6.5
[6] => 7
)
Array
(
[0] => -10
[1] => -7.2
[2] => -12
[3] => -3.7
[4] => -9.6
[5] => -1.7
[6] => -6.2
)
You can use array_filter function,
$positive = array_filter($ts, function ($v) {
return $v > 0;
});
$negative = array_filter($ts, function ($v) {
return $v < 0;
});
Note: This will skip values with 0, or you can just change condition to >=0 in positive numbers filter to considered in positive group.
DEMO.
The most elegant is to use phps array_filter() function:
<?php
$ts = [ 7,-10,13,8,4,-7.2,-12,-3.7,3.5,-9.6,6.5,-1.7,-6.2,7 ];
print_r( array_filter( $ts, function( $val ) { return (0>$val); } ) );
print_r( array_filter( $ts, function( $val ) { return ! (0>$val); } ) );
?>
If you are still using an older php version you need some longer implementation:
<?php
$ts = array( 7,-10,13,8,4,-7.2,-12,-3.7,3.5,-9.6,6.5,-1.7,-6.2,7 );
print_r( array_filter( $ts, create_function( '$val', 'return (0>$val);' ) ) );
print_r( array_filter( $ts, create_function( '$val', 'return ! (0>$val);' ) ) );
?>
Food for thought, you could write a generic function that splits an array based on a boolean result:
// splits an array based on the return value of the given function
// - add to the first array if the result was 'true'
// - add to the second array if the result was 'false'
function array_split(array $arr, callable $fn)
{
$a = $b = [];
foreach ($arr as $key => $value) {
if ($fn($value, $key)) {
$a[$key] = $value;
} else {
$b[$key] = $value;
}
}
return [$a, $b];
}
list($positive, $negative) = array_split($ts, function($item) {
return $item >= 0;
});
print_r($positive);
print_r($negative);
Demo
Rather than declaring two arrays, I recommend declaring one array with two subarrays. You can either give the subarrays an index of 0 or 1 depending on the conditional evaluation with zero, or you can go a little farther by declaring a lookup array to replace the integer key with an expressive word.
Regardless of if you choose to create one array or two arrays, you should only make one loop over the input array. Making two loops or by calling array_filter() twice is needlessly inefficient.
Code: (Demo)
$ts = [7,-10,13,8,4,-7.2,-12,-3.7,3.5,-9.6,6.5,-1.7,-6.2,7];
const KEY_NAMES = [0 => 'negative', 1 => 'non-negatuve'];
$result = [];
foreach ($ts as $v) {
$result[KEY_NAMES[$v >= 0]][] = $v;
}
var_export($result);
Output:
array (
'non-negatuve' =>
array (
0 => 7,
1 => 13,
2 => 8,
3 => 4,
4 => 3.5,
5 => 6.5,
6 => 7,
),
'negative' =>
array (
0 => -10,
1 => -7.2,
2 => -12,
3 => -3.7,
4 => -9.6,
5 => -1.7,
6 => -6.2,
),
)

Getting specidic values from PHP arrays

Is there a way to get the first value from array, then the first value key + 3 ; then +6 then + 9 ans so on
Take this array for example,
array(1,2,5,14,19,2,11,3,141,199,52,24,16)
i want extract a value every 3 so the result would be
array(1,14,11,199,16)
Can i do that with existing PHP array function?
Use a for loop and increment the counter variable by 3.
for ($i = 0; $i <= count(your array); $i+3) {
echo $myarray[i]
}
The following is function that will handle extracting the values from a given array. You can specify the number of steps between each value and if the results should use the same keys as the original. This should work with regular and associative arrays.
<?php
function extractValues($array, $stepBy, $preserveKeys = false)
{
$results = array();
$index = 0;
foreach ($array as $key => $value) {
if ($index++ % $stepBy === 0) {
$results[$key] = $value;
}
}
return $preserveKeys ? $results : array_values($results);
}
$array = array(1, 2, 5, 14, 19, 2, 11, 3, 141, 199, 52, 24, 16);
$assocArray = array('a' => 1, 'b' => 2, 'c' => 5, 'd' => 14, 'e' => 19, 'f' => 2, 11, 3, 141, 199, 52, 24, 16);
print_r(extractValues($array, 3));
print_r(extractValues($array, 3, true));
print_r(extractValues($assocArray, 5));
print_r(extractValues($assocArray, 5, true));
?>
Output
Array
(
[0] => 1
[1] => 14
[2] => 11
[3] => 199
[4] => 16
)
Array
(
[0] => 1
[3] => 14
[6] => 11
[9] => 199
[12] => 16
)
Array
(
[0] => 1
[1] => 2
[2] => 52
)
Array
(
[a] => 1
[f] => 2
[4] => 52
)
Use a loop and check the key.
$result = array();
foreach($array as $key => $value) {
if ($key % 3 === 0) {
$result[] = $value;
}
}
Try below one:
<?php
$your_array = array (1,2,5,14,19,2,11,3,141,199,52,24,16);
$every_3 = array();
$i = 0;
foreach($your_value as $value) {
$i++;
if($i%3==0){
$every_3[]=$value;
}
}
var_dump($every_3);
?>
Do like this
$arr=array (1,2,5,14,19,2,11,3,141,199,52,24,16);
$narr=array();
for($i=0;$i<count($arr);$i=$i+3){
$narr[]=$arr[$i]
}
print_r($narr);
<?php
$mynums = array(1,2,5,14,19,2,11,3,141,199,52,24,16);
foreach ($mynums as $key => $value) {
if ( $key % 3 === 0)
{
$newnum[] = $value;
}
}
var_dump($newnum);
?>
$data = array(1,2,5,14,19,2,11,3,141,199,52,24,16);
$matches = array();
foreach($data as $key => $value)
{
if($key%3 === 0)
{
$matches[] = $value;
}
}
var_dump($matches);
The only way you could do it would be to use a loop, count the length of an array, and loop through using a % mathmatical operator.
It gives you a remainder of a division: http://au2.php.net/operators.arithmetic

Unset associative array by value

I'd like to remove an array item by value. Key cannot be specified. Here is the array. I have sorted the array by value, numeric descending.
Array
(
[this] => 15
[that] => 10
[other] => 9
[random] => 8
[keys] => 4
)
If I want to unset all items that have a value less than 10. How do I do that?
Use the array_filter function:
$a = array_filter($a, function($x) { return !($x < 10); });
$test = array(
"this" => 15,
"that" => 10,
"other" => 9,
"random" => 8,
"keys" => 4
);
echo "pre: ";print_r($test);
pre: Array ( [this] => 15 [that] => 10 [other] => 9 [random] => 8 [keys] => 4 )
Run this code:
foreach($test AS $key => $value) {
if($value <= 10) {
unset($test[$key]);
}
}
Results are:
echo "post: ";print_r($test);
post: Array ( [this] => 15 )
foreach($array as $key => $value)
if( $value < 10 )
unset($array[$key])
Assuming that all values are ints:
for (i=9;i>=0;i--)
{
while (array_search($i, $assocArray) !== false)
{
unset($assocArray[array_search($i, $assocArray)]);
}
}
There probably are more elegant ways of doing this, but fever has a firm grip on my brain :)
knittl's answer is correct, but if you're using an older version of PHP, you can' t use the anonymous function, just do:
function filterFunc($v)
{
return $v >= 10;
}
$yourArray = array_filter($yourArray,'filterFunc');
Credit to Knittl

Categories