PHP: How to get last array element in one array - php

i am trying to create function to check if array element is the last array element in one array. Original array looks like:
array(1001,
1002,
array('exam'=>true, 'index'=>10),
1003,
1004,
1005,
array('exam'=>true, 'index'=>20),
1006,
1007,
array('exam'=>true, 'index'=>30),
1008,
1009
)
I this case to prove if "array('exam'=>true, 'index'=>30)" is the last.
I have index position of that element, but I do not know how to check if that is the last array element.
function is_last_exam_in_survey($array, $exam_position) {
foreach($array as $element) {
if(!is_numeric($element) {
// check if that is the last array element in array
//return true;
} else {
// return false;
}
}
}
I would be grateful for any advice:)

function get_last_exam_in_survey($array) {
$last = null;
foreach($array as $element) {
if(is_array($element) && !empty($element['exam'])) {
$last = $element;
}
}
return $last;
}
function is_last_exam_in_survey($array, $exam_position) {
$last_exam = get_last_exam_in_survey($array);
return !empty($last_exam) && ($last_exam['index']==$exam_position);
}

I think this would be the quickest solution:
function is_last_exam_in_survey($array, $exam_position) {
$last_index = array_key_last( $array );
if( $exam_position == $last_index ){
return true;
}else{
return false;
}
}
You can still change the conditional statement if you are trying to compare values from the last element, for example:
if( isset($last_index['index']) && $exam_position == $last_index['index'] ){
Also, if you want to get the latest array value instead of key, you could use this:
$last_index = end( $array );

I would reverse the array, and look for the first element. Something like:
function is_last_exam_in_survey($array, $exam_position) {
foreach(array_reverse($array) as $element) {
if(!is_numeric($element) {
return $element['index'] === $exam_position;
}
}
return false;
}
Seems like the most efficient and simplest solution to me.

this solution avoid loop. at first we find out the last index of array.Then we use is_array() function for check the last element is array or not.
function get_last_exam_in_survey(array $arr)
{
$lastOfset = count($arr) - 1;
if(is_array($arr[$lastOfset])){
return true;
}else{
return false;
}
}

I think you can use array_column function to do that
function is_last_exam_in_survey($array,$exam_position){
$ac = array_column($array, 'index'); // return array(10,20,30)
$la = $ac[count($ac) - 1]; // 30
foreach ($array as $element) {
if (!is_numeric($element)) {
// check if $element['index'] === 30
if($element['index'] === $la){
return true;
}
}
}
}

How about using array_slice to extract the values in the array that are after the position you are looking at, then array_filter to remove any values that are not arrays. If there are any values left, then the entry you are looking at is not the last array entry in the array.
This may not be very efficient if you are calling it a lot of times with a large array. It may be better to rethink the way the data is stored or loaded into the array.
function is_last_exam_in_survey($array, $exam_position)
{
return isset($array[$exam_position])
&& is_array($array[$exam_position])
&& !array_filter(array_slice($array, $exam_position + 1), 'is_array');
}

Related

Check if a value exists multidimensional array and return its key

I have an array, say
$updates = array();
$updates['U1'] = array('F1', 'F2', 'F5');
$updates['U2'] = array('F3');
$updates['U3'] = array('F3', 'F4');
I need search for a value say F5 so it should return the key U1.
And also if there is multiple occurrence of a value, should return the last key.
Eg. searching F3 should return U3 and not U2.
I have searched a lot and can't find a way. I am looking for a solution without using loops.
without using loop:
function findArrVal($arr = [], $param){
static $indx = 0;
if($indx == 0){
krsort($arr);
}
$keys = array_keys($arr);
$values = array_values($arr);
if( count($values) == $indx ){
return false;
} else if( is_array($values[$indx]) && in_array($param, $values[$indx])){
return $keys[$indx];
} else {
++$indx;
return findArrVal($arr, $param);
}
return FALSE;
}
using loop:
function findArrVal($arr = [], $param){
krsort($arr);
foreach($arr as $key => $ar){
if(is_array($ar) && in_array($param, $ar)){
return $key;
}
}
return FALSE;
}
findArrVal($updates,'F3');
krsort - sorts the array in reverse order. ( to find the value at first occurrence )
is_array to check if the child value is an array type.
in_array to find the item on the child array.
Maybe It's helpful for you.
function _getFindArrayKey(array $arr, $key)
{
if (array_key_exists($key, $arr)) {
return true;
}
// check arrays contained in this array
foreach ($arr as $element) {
if (is_array($element)) {
if (_getFindArrayKey($element, $key)) {
return true;
}
}
}
return false;
}

PHP In_MultiArray Function

on http://php.net/manual/en/function.in-array.php - if you scroll down it gives a function to determine if a string is inside of a query in a multidimensional array. "If you found yourself in need of a multidimensional array in_array like function you can use the one below. Works in a fair amount of time"
Here's original code(working):
function in_multiarray($elem, $array)
{
$top = sizeof($array) - 1;
$bottom = 0;
while($bottom <= $top)
{
if($array[$bottom] == $elem)
return true;
else
if(is_array($array[$bottom]))
if(in_multiarray($elem, ($array[$bottom])))
return true;
$bottom++;
}
return false;
}
What I'm trying to do is instead of returning 'true' or 'false' - i'd like to return the ROW #. So my initial thought was to simply replace 'return true' with 'return $bottom; however it isn't returning the record number.
Modified Function (not working);
function in_multiarray($elem, $array)
{
$top = sizeof($array) - 1;
$bottom = 0;
while($bottom <= $top)
{
if($array[$bottom] == $elem)
return $bottom;
else
if(is_array($array[$bottom]))
if(in_multiarray($elem, ($array[$bottom])))
return $bottom;
$bottom++;
}
return false;
}
Does anyone have an idea how to modify this function to return the ROW number that contains the match?
Here's a sample of the array...
$sample = array
array ("oldpage1.php","newpage1.php"),
array ("oldpage2.php","newpage2.php"),
array ("oldpage3.php","newpage3.php"),
array ("oldpage4.php","newpage4.php"),
array ("oldpage5.php","newpage5.php")
etc.
);
$row = in_multiarray($input, $sample);
Therefore if we know the row # we can fetch the new page with a simple
$newpage=$sample[$row][1]
Thanks!
It's worth noting that a function like in_array is intended to tell you whether or not a value exists inside of an array. What you're looking for seems to be a lot closer to something like array_search, which is designed to actually provide you with the key that points to a given value in the array.
However, because you're using a multi-dimensional array what you're actually looking for is the key that points to the array that contains the value. Hence we can divide and conquer this problem with two simple steps.
Map
Filter
The first step is to map a function in_array to every element in the first array (which is just another array). This will tell us which elements of the primary array contain an array that contains the value we're searching for.
$result = array_map(function($arr) use($search) {
return in_array($search, $arr, true);
}, $arr, [$searchValue]);
The second step is to then return the keys to those arrays (i.e. filter the result).
$keys = array_keys(array_filter($result));
Now you have all the keys of any matching items. If you want to apply as just one custom filter that specifies exactly where in the subarray to look, you could also do it like this.
$search = "oldpage2.php";
$sample = [
["oldpage1.php","newpage1.php"],
["oldpage2.php","newpage2.php"],
["oldpage3.php","newpage3.php"],
["oldpage4.php","newpage4.php"],
["oldpage5.php","newpage5.php"],
];
$keys = array_keys(array_filter($sample, function($arr) use($search) {
return $arr[0] === $search;
}));
var_dump($keys);
And you get...
array(1) {
[0]=>
int(1)
}
So now you know that "oldpage2.php" is in row 1 in $sample[1][0] which means you can do this to get the results out of the array.
foreach($keys as $key) {
echo "{$sample[$key][0]} maps to {$sample[$key][1]}\n";
}
Giving you
oldpage2.php maps to newpage2.php
If you want to return only the first result you could do that as well with a function like this using similar approach.
function getFirstMatch($search, Array $arr) {
foreach($arr as $key => $value) {
if ($value[0] === $search) {
return $value[1];
}
}
}
echo getFirstMatch("oldpage4.php", $sample); // newpage4.php
The Better Alternative
Of course, the better approach is to actually use the oldpage names as the actual keys of the array rather than do this expensive search through the array, because array lookup by key in PHP is just an O(1) operation, whereas this needle/haystack approach is O(N).
So we turn your $samples array into something like this and the search no longer requires any functions...
$samples = [
"oldpage1.php" => "newpage1.php",
"oldpage2.php" => "newpage2.php",
"oldpage3.php" => "newpage3.php",
"oldpage4.php" => "newpage4.php",
"oldpage5.php" => "newpage5.php",
];
Now you can just do something like $newpage = $samples[$search] and you get exactly what you're looking for. So echo $samples["oldpage2.php"] gives you "newpage2.php" directly without the intermediary step of searching through each array.
You can use the following code to get the full path to the value:
function in_multiarray($elem, $array, &$result)
{
$top = sizeof($array) - 1;
$bottom = 0;
while($bottom <= $top)
{
if($array[$bottom] == $elem) {
array_unshift($result, $bottom);
return true;
}
else {
if(is_array($array[$bottom])) {
if(in_multiarray($elem, $array[$bottom], $result)) {
array_unshift($result, $bottom);
return true;
}
}
}
$bottom++;
}
array_shift($result);
return false;
}
$sample = array(
array ("oldpage1.php","newpage1.php"),
array ("oldpage2.php","newpage2.php"),
array ("oldpage3.php","newpage3.php"),
array ("oldpage4.php","newpage4.php"),
array ("oldpage5.php","newpage5.php")
);
$input = "newpage5.php";
$result = [];
in_multiarray($input, $sample, $result);
print_r($result);
Path is stored in $result;

Converting a string with comma separated value in a tree in PHP

I have a csv file that contains a field with a category tree in a comma separated format like this:
MotherCategory, ChildCategory1, ChildCategory2, ecc.
Some records contains only a category, other ones two, other ones three or more.
I would like to be able to store in my db all the unique categories and organise every record with a parentid scheme where the parentid value is the id of the category one level up.
At the end I should have something like:
id: 1, catname: MotherCategory, parentid: NULL
id: 2, catname: ChildCategory1, parentid: 1
id: 3, catname: ChildCategory2, parentid: 2
I've already filtered the data removing duplicates with array_unique(), next using explode() I am able to separate the values and I was counting the values and separating the groups basing on the length of the resultant arrays to build a tree, but I think that at the moment I am missing something to get my final result.
I've the following code. Can someone please give me a hint to solve the problem?
$cats = array_of_comma_separated_values;
foreach ($cats as $cat) {
$catarray[] = explode(",",$cat);
}
//first level
$level1 = array_filter ($catarray, function($item) {
if (count($item) == 1) { return true; } return false;
});
//second level
$level2 = array_filter ($catarray, function($item) {
if (count($item) == 2) { return true; } return false;
});
$level3 = array_filter ($catarray, function($item) {
if (count($item) == 3) { return true; } return false;
});
$level4 = array_filter ($catarray, function($item) {
if (count($item) == 4) { return true; } return false;
});
$level5 = array_filter ($catarray, function($item) {
if (count($item) == 5) { return true; } return false;
});
$level6 = array_filter ($catarray, function($item) {
if (count($item) == 6) { return true; } return false;
});
$level7 = array_filter ($catarray, function($item) {
if (count($item) == 7) { return true; } return false;
});
This gives me several arrays that i've to iterate to achieve what i'm looking for.
Now thanks to the suggestion from Kovlar I'm working on something based on array_pop() and array_replace_recurive().
I've edited the post because maybe I was not so clear.
I suggest the use of array_replace_recursive() to simplify the tree-merging :)
// $tree will contain the tree at the end of the script
$tree = [];
// we treat each row of the csv one by one
foreach($csv_rows as $row) {
// first, we split the string into an array
$root_to_leaf = explode(',', $row['root_to_leaf']);
// this is the "leaf" we want to append to the tree
$leaf = [array_pop($root_to_leaf) => $row['value']];
// we rebuild the path from the leaf to the root
while(!empty($root_to_leaf)) {
// add the next branching toward the root
$leaf = [array_pop($root_to_leaf) => $leaf];
}
// we append the leaf to the tree
$tree = array_replace_recursive($tree, $leaf);
}

PHP Function that can return value from an array key a dynamic number of levels deep

Using PHP, I would like to write a function that accomplishes what is shown by this pseudo code:
function return_value($input_string='array:subArray:arrayKey')
{
$segments = explode(':',$input_string);
$array_depth = count(segments) - 1;
//Now the bit I'm not sure about
//I need to dynamically generate X number of square brackets to get the value
//So that I'm left with the below:
return $array[$subArray][$arrayKey];
}
Is the above possible? I'd really appreciate some pointer on how to acheive it.
You can use a recursive function (or its iterative equivalent since it's tail recursion):
function return_value($array, $input_string) {
$segments = explode(':',$input_string);
// Can we go next step?
if (!array_key_exists($segments[0], $array)) {
return false; // cannot exist
}
// Yes, do so.
$nextlevel = $array[$segments[0]];
if (!is_array($nextlevel)) {
if (1 == count($segments)) {
// Found!
return $nextlevel;
}
// We can return $nextlevel, which is an array. Or an error.
return false;
}
array_shift($segments);
$nextsegments = implode(':', $segments);
// We can also use tail recursion here, enclosing the whole kit and kaboodle
// into a loop until $segments is empty.
return return_value($nextlevel, $nextsegments);
}
Passing one object
Let's say we want this to be an API and pass only a single string (please remember that HTTP has some method limitation in this, and you may need to POST the string instead of GET).
The string would need to contain both the array data and the "key" location. It's best if we send first the key and then the array:
function decodeJSONblob($input) {
// Step 1: extract the key address. We do this is a dirty way,
// exploiting the fact that a serialized array starts with
// a:<NUMBEROFITEMS>:{ and there will be no "{" in the key address.
$n = strpos($input, ':{');
$items = explode(':', substr($input, 0, $n));
// The last two items of $items will be "a" and "NUMBEROFITEMS"
$ni = array_pop($items);
if ("a" != ($a = array_pop($items))) {
die("Something strange at offset $n, expecting 'a', found {$a}");
}
$array = unserialize("a:{$ni}:".substr($input, $n+1));
while (!empty($items)) {
$key = array_shift($items);
if (!array_key_exists($key, $array)) {
// there is not this item in the array.
}
if (!is_array($array[$key])) {
// Error.
}
$array = $array[$key];
}
return $array;
}
$arr = array(
0 => array(
'hello' => array(
'joe','jack',
array('jill')
)));
print decodeJSONblob("0:hello:1:" . serialize($arr));
print decodeJSONblob("0:hello:2:0" . serialize($arr));
returns
jack
jill
while asking for 0:hello:2: would get you an array { 0: 'jill' }.
you could use recursion and array_key_exists to walk down to the level of said key.
function get_array_element($key, $array)
{
if(stripos(($key,':') !== FALSE) {
$currentKey = substr($key,0,stripos($key,':'));
$remainingKeys = substr($key,stripos($key,':')+1);
if(array_key_exists($currentKey,$array)) {
return ($remainingKeys,$array[$currentKey]);
}
else {
// handle error
return null;
}
}
elseif(array_key_exists($key,$array)) {
return $array[$key];
}
else {
//handle error
return null;
}
}
Use a recursive function like the following or a loop using references to array keys
<?php
function lookup($array,$lookup){
if(!is_array($lookup)){
$lookup=explode(":",$lookup);
}
$key = array_shift($lookup);
if(!isset($array[$key])){
//throw exception if key is not found so false values can also be looked up
throw new Exception("Key does not exist");
}else{
$val = $array[$key];
if(count($lookup)){
return lookup($val,$lookup);
}
return $val;
}
}
$config = array(
'db'=>array(
'host'=>'localhost',
'user'=>'user',
'pass'=>'pass'
),
'data'=>array(
'test1'=>'test1',
'test2'=>array(
'nested'=>'foo'
)
)
);
echo "Host: ".lookup($config,'db:host')."\n";
echo "User: ".lookup($config,'db:user')."\n";
echo "More levels: ".lookup($config,'data:test2:nested')."\n";
Output:
Host: localhost
User: user
More levels: foo

Getting a value into multidimensional array from a list of indexes (array too)

I'm looking for a nice way of doing the magicFunction():
$indexes = array(1, 3, 0);
$multiDimensionalArray = array(
'0',
array('1-0','1-1','1-2',array('2-0','2-1','2-2')),
array('1-4','1-5','1-6')
);
$result = magicFunction($indexes, $multiDimensionalArray);
// $result == '2-0', like if we did $result = $multiDimensionalArray[1][3][0];
Thanks.
You can solve this recursively.
$indexes = array(1, 3, 0);
$multiDimensionalArray = array(
'0',
array('1-0','1-1','1-2',array('2-0','2-1','2-2')),
array('1-4','1-5','1-6')
);
$result = magicFunction($indexes, $multiDimensionalArray);
function magicFunction($indices, $array) {
// Only a single index is left
if(count($indices) == 1) {
return $array[$indices[0]];
} else if(is_array($indices)) {
$index = array_shift($indices);
return magicFunction($indices, $array[$index]);
} else {
return false; // error
}
}
print $result;
This function will go down the $multiDimensionalArray as long as there are indices available and then return the last value accesses by the index. You will need to add some error handling though, e.g. what happens if you call the function with $indexes = array(1,2,3,4);?
This is a recursive version. Will return null if it cannot find a value with the given index route.
function magicFunction($indexes, $array) {
if (count($indexes) == 1) {
return isset($array[$indexes[0]]) ? $array[$indexes[0]] : null;
} else {
$index=array_shift($indexes);
return isset($array[$index]) ? magicFunction($indexes, $array[$index]) : null;
}
}
You can just step trough based on your keys (no need to do any recursion, just a simple foreach):
$result = &$multiDimensionalArray;
foreach($indexes as $index)
{
if (!isset($result[$index]))
break; # Undefined index error
$result = &$result[$index];
}
If you put it inside a function, then it won't keep the reference if you don't want to. Demo.
I think something like this should do the trick for you.
function magicFuntion($indexes, $marray)
{
if(!is_array($indexes) || count($indexes) == 0 || !is_array($marray))
return FALSE;
$val = '';
$tmp_arr = $marray;
foreach($i in $indexes) {
if(!is_int($i) || !is_array($tmp_arr))
return FALSE;
$val = $tmp_arr[$i];
$tmp_arr = $tmp_arr[$i];
}
return $val;
}
Try this :P
function magicFunction ($indexes,$mdArr){
if(is_array($mdArr[$indexes[0]] && $indexes)){
magicFunction (array_slice($indexes,1),$mdArr[$indexes[0]]);
}
else {
return $mdArr[$indexes[0]];
}
}
My own attempt ; found it simpler by not doing it recursively, finally.
function magicFunction($arrayIndexes, $arrayData)
{
if (!is_array($arrayData))
throw new Exception("Parameter 'arrayData' should be an array");
if (!is_array($arrayIndexes))
throw new Exception("Parameter 'arrayIndexes' should be an array");
foreach($arrayIndexes as $index)
{
if (!isset($arrayData[$index]))
throw new Exception("Could not find value in multidimensional array with indexes '".implode(', ', $arrayIndexes)."'");
$arrayData = $arrayData[$index];
}
return $arrayData;
}
Exceptions may be somewhat "violent" here, but at least you can know exactly what's going on when necessary.
Maybe, for sensitive hearts, a third $defaultValue optional parameter could allow to provide a fallback value if one of the indexes isn't found.

Categories