Get the last dimension of each element of an array - php

I have an array that might be any depth or number of elements:
$ra['a'] = 'one';
$ra['b']['two'] = 'b2';
$ra['c']['two']['three'] = 'c23';
$ra['c']['two']['four'] = 'c24';
$ra['c']['five']['a'] = 'c5a';
I want to have an array of the strings, like this:
array (
0 => 'one',
1 => 'b2',
2 => 'c23',
3 => 'c24',
4 => 'c5a',
)
Here is a recursive function I made. It seems to work. But I'm not sure that I'm doing it right, as far as declaring the static, and when to unset the static var (in case I want to use the function again, I dont want that old static array)
function lastthinggetter($ra){
static $out;
foreach($ra as $r){
if(is_array($r))
lastthinggetter($r);
else
$out[] = $r;
}
return $out;
}
How do I make sure each time I call the function, the $out var is fresh, every time? Is there a better way of doing this?
Maybe check if we're in recursion?
function lastthinggetter($ra, $recurse=false){
static $out;
foreach($ra as $r){
if(is_array($r))
lastthinggetter($r, true);
else
$out[] = $r;
}
$tmp = $out;
if(!$recurse)
unset($out);
return $tmp;
}

Your last version will probably work correctly. However, if you want to get rid of the static variable you could also do it like this:
function getleaves($ra) {
$out=array();
foreach($ra as $r) {
if(is_array($r)) {
$out=array_merge($out,getleaves($r));
}
else {
$out[] = $r;
}
}
return $out;
}
The key here is, that you actually return the so far found values at the end of your function but so far you have not 'picked them up' in the calling part of your script. This version works without any static variables.

I'll simply use array_walk_recursive over here instead like as
array_walk_recursive($ra, function($v)use(&$result) {
$result[] = $v;
});
Demo

Related

Maintain Element in PHP Array And Update in PHP Class

I have one PHP class as below (part of the code):
class myclass{
private static $arrX = array();
private function is_val_exists($needle, $haystack) {
if(in_array($needle, $haystack)) {
return true;
}
foreach($haystack as $element) {
if(is_array($element) && $this->is_val_exists($needle, $element))
return true;
}
return false;
}
//the $anInput is a string e.g. Michael,18
public function doProcess($anInput){
$det = explode(",", $anInput);
if( $this->is_val_exists( $det[0], $this->returnProcess() ) ){
//update age of Michael
}
else{
array_push(self::$arrX, array(
'name' => $det[0],
'age' => $det[1]
));
}
}
public function returnProcess(){
return self::$arrX;
}
}
The calling code in index.php
$msg = 'Michael,18';
myclass::getHandle()->doProcess($msg);
In my webpage says index.php, it calls function doProcess() over and over again. When the function is called, string is passed and stored in an array. In the next call, if let's say same name is passed again, I want to update his age. My problem is I don't know how to check if the array $arrX contains the name. From my own finding, the array seems to be re-initiated (back to zero element) when the code is called. My code never does the update and always go to the array_push part. Hope somebody can give some thoughts on this. Thank you.
There is a ) missing in your else condition of your doProcess() function, it should read:
else{
array_push(self::$arrX, array(
'name' => $det[0],
'age' => $det[1]
)); // <-- there was the missing )
}
Here is a complete running solution based on your code:
<?php
class myclass{
private static $arrX = array();
private function is_val_exists($needle, $haystack) {
if(in_array($needle, $haystack)) {
return true;
}
foreach($haystack as $element) {
if(is_array($element) && $this->is_val_exists($needle, $element))
return true;
}
return false;
}
//the $anInput is a string e.g. Michael,18
public function doProcess($anInput){
$det = explode(",", $anInput);
if( $this->is_val_exists( $det[0], $this->returnProcess() ) ){
//update age of Michael
for ($i=0; $i<count(self::$arrX); $i++) {
if (is_array(self::$arrX[$i]) && self::$arrX[$i]['name'] == $det[0]) {
self::$arrX[$i]['age'] = $det[1];
break;
}
}
} else{
array_push(self::$arrX, array(
'name' => $det[0],
'age' => $det[1]
));
}
}
public function returnProcess(){
return self::$arrX;
}
}
$mc = new myclass();
$mc->doProcess('Michael,18');
$mc->doProcess('John,23');
$mc->doProcess('Michael,19');
$mc->doProcess('John,25');
print_r($mc->returnProcess());
?>
You can test it here: PHP Runnable
As I said in comments, it looks like you want to maintain state between requests. You can't use pure PHP to do that, you should use an external storage solution instead. If it's available, try Redis, it has what you need and is quite simple to use. Or, if you're familiar with SQL, you could go with MySQL for example.
On a side note, you should read more about how PHP arrays work.
Instead of array_push, you could have just used self::$arrX[] = ...
Instead of that, you could have used an associative array, e.g. self::$arrX[$det[0]] = $det[1];, that would make lookup much easier (array_key_exists etc.)
Can you try updating the is_val_exists as follows:
private function is_val_exists($needle, $haystack) {
foreach($haystack as $element) {
if ($element['name'] == $needle) {
return true;
}
return false;
}

Call a function within a function display both within array

how do I call a function from within a function?
function tt($data,$s,$t){
$data=$data;
echo '[[';
print_r($data);
echo ']]';
if($t==0){
$data[]=$s;
tt($data,'two',1);
}else{
$data[]=$s;
}
return $data;
}
print_r(tt('','one',0));
I want 'two' to be shown within the array like
$o[]='one';
$o[]='two';
print_r($o);
function tt($s, $t, array $data = array()) {
$data[] = $s;
if ($t == 0) {
$data = tt('two', 1, $data);
}
return $data;
}
print_r(tt('one', 0));
This is all that's really needed.
Put the array as the last argument and make it optional, because you don't need it on the initial call.
When calling tt recursively, you need to "catch" its return data, otherwise the recursive call simply does nothing of lasting value.
No need for the else, since you're going to append the entry to the array no matter what and don't need to write that twice.
Try this one (notice the function signature, the array is passed by ref &$data):
function tt(&$data,$s,$t){
echo '[[';
print_r($data);
echo ']]';
if($t==0){
$data[]=$s;
tt($data,'two',1);
}else{
$data[]=$s;
}
return $data;
}
$array = [];
tt($array,'one',0);
print_r($array);
/**
Array
(
[0] => one
[1] => two
)
*/
try this
function tt($data,$s,$t){
global $data;
if($t==0){
$data[]=$s;
tt($data,'two',1);
}else{
$data[]=$s;
}
return $data;
}
print_r(tt('','one',0));
OUTPUT :
Array
(
[0] => one
[1] => two
)
DEMO

Recursive function with unknown depth of values. Return all values (undefined depth)

I have a question about a recursive PHP function.
I have an array of ID’s and a function, returning an array of „child id’s“ for the given id.
public function getChildId($id) {
…
//do some stuff in db
…
return childids;
}
One childid can have childids, too!
Now, I want to have an recursive function, collecting all the childids.
I have an array with ids like this:
$myIds = array("1111“,"2222“,"3333“,“4444“,…);
and a funktion:
function getAll($myIds) {
}
What I want: I want an array, containing all the id’s (including an unknown level of childids) on the same level of my array. As long as the getChildId($id)-function is returning ID’s…
I started with my function like this:
function getAll($myIds) {
$allIds = $myIds;
foreach($myIds as $mId) {
$childids = getChildId($mId);
foreach($childids as $sId) {
array_push($allIds, $sId);
//here is my problem.
//what do I have to do, to make this function rekursive to
//search for all the childids?
}
}
return $allIds;
}
I tried a lot of things, but nothing worked. Can you help me?
Assuming a flat array as in your example, you simply need to call a function that checks each array element to determine if its an array. If it is, the function calls it itself, if not the array element is appended to a result array. Here's an example:
$foo = array(1,2,3,
array(4,5,
array(6,7,
array(8,9,10)
)
),
11,12
);
$bar = array();
recurse($foo,$bar);
function recurse($a,&$bar){
foreach($a as $e){
if(is_array($e)){
recurse($e,$bar);
}else{
$bar[] = $e;
}
}
}
var_dump($bar);
DEMO
I think this code should do the trick
function getAll($myIds) {
$allIds = Array();
foreach($myIds as $mId) {
array_push($allIds, $mId);
$subids = getSubId($mId);
foreach($subids as $sId) {
$nestedIds = getAll($sId);
$allIds = array_merge($allIds, $nestedIds);
}
}
return $allIds;
}

How to Promote certain elements to the start of an array in PHP

If certain elements are contained in an array, I want them moved to the start of it.
At first I used a bunch of array_diff_keys to get it to work, but I wanted something more elegant. So I tried using uksort with a callback, but perhaps I'm doing it wrong because it's not working.
I tried this, it's a method of my helper class, but it's not working.
$good_elements = array('sku','name','type','category','larping');
$test_array = array('sku','name','asdf','bad_stuff','larping','kwoto');
$results = helper::arrayPromoteElementsIfExist($test_array,$good_elements,false);
public static function arrayPromoteElementsIfExist($test_array,$promote_elements,$use_keys = false) {
foreach(array('test_array','promote_elements') as $arg) {
if(!is_array($$arg)) {
debug::add('errors',__FILE__,__LINE__,__METHOD__,'Must be array names',$$arg);
return false;
}
}
if(!$use_keys) {
$test_array = array_flip($test_array); // compare keys
$promote_elements = array_flip($promote_elements); // compare keys
}
uksort($test_array,function($a,$b) use($promote_elements) {
$value1 = intval(in_array($a, $promote_elements));
$value2 = intval(in_array($b,$promote_elements));
return $value1 - $value2;
});
if(!$use_keys) {
$test_array = array_flip($test_array);
}
return $test_array;
}
Fairly quick and dirty but here you go.
function promoteMembers($input, $membersToPromote)
{
$diff = array_diff($input, $membersToPromote);
return array_merge($membersToPromote, $diff);
}
Assuming I understood what you wanted to do.
Example output: for your verification.

Creating an instance of a php key-value pair without an array

I'm writing a recursive function to construct a multidimensional array. Basically, the problem is as follows:
function build($term){
$children = array();
foreach ( $term->children() as $child ) {
$children[] = build($child);
}
if(!count($children)){
return $term->text();
} else {
return $term->text() => $children; //obviously, this doesn't work
}
}
Thoughts? I know I could rewrite the structure of the function to make it work, but it seems like that should be unnecessary.
function build($term){
$children = array();
foreach ( $term->children() as $child ) {
$children += build($child);
}
if(!count($children)){
return $term->text();
} else {
return array($term->text() => $children); //obviously, this doesn't work
}
}
From what i understand of the question this is what it should look like.
Appending the recursion and returning an array.
Edit: as an aside you might be better off returning an array even if count($children) ==0, this would get all of your types inline. else you may get all sorts of errors down the line:
if(!count($children)){
return array($term->text() => null);
An array is the only key-value pair container PHP has to offer. So you HAVE to use an array if you want your function (may it be recursive or not) to return a key-value pair.
return array($term->text() => $children);
You could return it like this:
return array($term->text() => $children);
Although it's not what you asked. I think you cannot do this without rewriting parts of your function, one way or another.

Categories