Retrieve first key in multi-dimensional array using PHP - php

I would like to retrieve the first key from this multi-dimensional array.
Array
(
[User] => Array
(
[id] => 2
[firstname] => first
[lastname] => last
[phone] => 123-1456
[email] =>
[website] =>
[group_id] => 1
[company_id] => 1
)
)
This array is stored in $this->data.
Right now I am using key($this->data) which retrieves 'User' as it should but this doesn't feel like the correct way to reach the result.
Are there any other ways to retrieve this result?
Thanks

There are other ways of doing it but nothing as quick and as short as using key(). Every other usage is for getting all keys. For example, all of these will return the first key in an array:
$keys=array_keys($this->data);
echo $keys[0]; //prints first key
foreach ($this->data as $key => $value)
{
echo $key;
break;
}
As you can see both are sloppy.
If you want a oneliner, but you want to protect yourself from accidentally getting the wrong key if the iterator is not on the first element, try this:
reset($this->data);
reset():
reset() rewinds array 's internal
pointer to the first element and
returns the value of the first array
element.
But what you're doing looks fine to me. There is a function that does exactly what you want in one line; what else could you want?

Use this (PHP 5.5+):
echo reset(array_column($this->data, 'id'));

I had a similar problem to solve and was pleased to find this post. However, the solutions provided only works for 2 levels and do not work for a multi-dimensional array with any number of levels. I needed a solution that could work for an array with any dimension and could find the first keys of each level.
After a bit of work I found a solution that may be useful to someone else and therefore I included my solution as part of this post.
Here is a sample start array:
$myArray = array(
'referrer' => array(
'week' => array(
'201901' => array(
'Internal' => array(
'page' => array(
'number' => 201,
'visits' => 5
)
),
'External' => array(
'page' => array(
'number' => 121,
'visits' => 1
)
),
),
'201902' => array(
'Social' => array(
'page' => array(
'number' => 921,
'visits' => 100
)
),
'External' => array(
'page' => array(
'number' => 88,
'visits' => 4
)
),
)
)
)
);
As this function needs to display all the fist keys whatever the dimension of the array, this suggested a recursive function and my function looks like this:
function getFirstKeys($arr){
$keys = '';
reset($arr);
$key = key($arr);
$arr1 = $arr[$key];
if (is_array($arr1)){
$keys .= $key . '|'. getFirstKeys($arr1);
} else {
$keys = $key;
}
return $keys;
}
When the function is called using the code:
$xx = getFirstKeys($myArray);
echo '<h4>Get First Keys</h4>';
echo '<li>The keys are: '.$xx.'</li>';
the output is:
Get First Keys
The keys are: referrer|week|201901|Internal|page|number
I hope this saves someone a bit of time should they encounter a similar problem.

Related

How to remove duplicate arrays from a multi dimensional array?

I have a large multidimensional array that looks like the below.
I want to remove duplicate arrays based on the ID, however, I am struggling to achieve this.
I want the duplicates to work over the entire array, so you can see that ID 1229873 is a duplicate, in the array 2021-07-07 and 2021-07-09, it should therefore be removed from 2021-07-09
How would I achieve this? array_unique has not worked for me.
$data = array (
'2021-07-07' =>
array (
0 =>
array (
'id' => 5435435,
'homeID' => 8754,
'match_url' => '/usa/reading-united-ac-vs-ocean-city-noreasters-fc-h2h-stats#1229873',
'competition_id' => 5808,
'matches_completed_minimum' => 12,
),
1 =>
array (
'id' => 1229873,
'homeID' => 8754,
'match_url' => '/usa/reading-united-ac-vs-ocean-city-noreasters-fc-h2h-stats#1229873',
'competition_id' => 5808,
'matches_completed_minimum' => 12,
),
),
'2021-07-09' =>
array (
0 =>
array (
'id' => 3243234,
'homeID' => 8754,
'match_url' => '/usa/reading-united-ac-vs-ocean-city-noreasters-fc-h2h-stats#1229873',
'competition_id' => 5808,
'matches_completed_minimum' => 12,
),
1 =>
array (
'id' => 1229873,
'homeID' => 8754,
'match_url' => '/usa/reading-united-ac-vs-ocean-city-noreasters-fc-h2h-stats#1229873',
'competition_id' => 5808,
'matches_completed_minimum' => 12,
),
),
);
This is a perfect case for array_uunique()! No wait, scratch that. The PHP devs refused to implement it for the perfectly valid reason of... [shuffles notes] "the function name looks like a typo".
[sets notes on fire]
Anyhow, you just need to iterate over that data, keep track of the IDs you've seen, and remove entries that you've already seen.
$seen = [];
foreach(array_keys($data) as $i) {
foreach(array_keys($data[$i]) as $j) {
$id = $data[$i][$j]['id'];
if( in_array($id, $seen) ) {
unset($data[$i][$j]);
} else {
$seen[] = $id;
}
}
}
I've opted for the foreach(array_keys(...) as $x) approach as avoiding PHP references is always the sane choice.
Run it.
I am Sure That is the way which you want to get the unique array.
$unique = array_map("unserialize", array_unique(array_map("serialize", $data)));
echo "<pre>";
print_r($unique);
echo "</pre>";

Remove similar from foreach

Trying use array_unique but this did not help, since not all fields are repeated for me.
My array:
'Rows' =>
array (
0 =>
array (
'HotelId' => 94852,
'OfferId' => 858080496,
'OfferIdStr' => '858080496',
'Price' => 2762,
),
1 =>
array (
'HotelId' => 94852,
'OfferId' => 858080497,
'OfferIdStr' => '858080497',
'Price' => 3000,
),
And my try:
$allHotels['Rows'] = array_unique($allHotels['Rows'], SORT_REGULAR);
Changed flags, didn't help either (SORT_NORMAL, etc...).
It deletes absolutely everything, i need to ignore the HotelId replay, only first need.
If you want to delete duplicated entries based solely on the HotelId value, it's probably easiest just to iterate over the array, storing the seen HotelId values and deleting the current entry if it's HotelId value has already been seen.
$seenHotels = array();
foreach ($allHotels['Rows'] as $key => $hotel) {
if (in_array($hotel['HotelId'], $seenHotels)) {
unset($allHotels['Rows'][$key]);
}
else {
$seenHotels[] = $hotel['HotelId'];
}
}
print_r($allHotels);
Demo on 3v4l.org

Replace value in multidimensional php array

First, I have to say I already checked some answers but neither it wasn't exactly what I was looking for neither I couldn't fully understand the answer and how to use it.
I have this MultiDimensional array:
Array
(
[field_5abcb693a68bc] => Array
(
[0] => Array
(
[field_5abcbb1b51ddf] => mortgage
[field_5ae58a0b58b58] =>
[field_5abcbb1e51de0] => 10
[field_5abcbb2051de1] => הידגלה
[field_5abcbb2351de2] => 45,654,456
[field_5abcbb6251de3] =>
[field_5abcbb6651de4] => 04/2017
[field_5abcbb6851de5] => 4,454,656
[field_5abcbb6b51de6] => 24/07/2018
[field_5abcbbb351de7] => 657
[field_5abcbbb651de8] => 24/07/2018
[field_5abcbbb851de9] => 15
[field_5abcbbbb51dea] => yes
)
)
)
And I want to find values that much the pattern of mm/yyyy. Regex is a good option, I know how to write the condition:
if ( preg_match('/^\d[1-9]\/[1-9][0-9][0-9][0-9]$/',$v) ) {
//do stuff
}
I want to look in the inner part of the array for this pattern, and if it is a match, to change the value in the array to
$value = '01/' . $value;
means the value '04/2017' changes to '01/04/2017'.
note: there can be more than one value to change.
note: the name of the first array within the array [field_5abcb693a68bc] can vary and won't stay the same in other cases.
Thanks.
Use array_walk_recursive with reference to value as argument instead of regular value argument of callback.
It would work like that:
array_walk_recursive(
$array,
function (&$value) {
if (preg_match('/^\d[1-9]\/[1-9][0-9][0-9][0-9]$/',$value)) {
$value = '01/' . $value;
}
}
);
Check result on 3v4l.org
You want to perform a conditional replacement using a regex pattern? preg_replace() seems sensible. preg_replace() is happy to iterate a one-dimensional array, so the lowest level can be directly served to it.
Notice that I've changed the pattern delimiter to avoid escaping the forward slash. I've also made the pattern more brief by using \d and the {3} quantifier. $0 means the "fullstring match". You don't have to write the unset() call to purge those temporary variables, but some developers consider it to be best practice because it avoids potential variable conflict down-script.
Code: (Demo)
$array = [
'field_5abcb693a68bc' => [
0 => [
'field_5abcbb1b51ddf' => 'mortgage',
'field_5ae58a0b58b58' => '',
'field_5abcbb1e51de0' => '10',
'field_5abcbb2051de1' => 'הידגלה',
'field_5abcbb2351de2' => '45,654,456',
'field_5abcbb6251de3' => '',
'field_5abcbb6651de4' => '04/2017',
'field_5abcbb6851de5' => '4,454,656',
'field_5abcbb6b51de6' => '24/07/2018',
'field_5abcbbb351de7' => '657',
'field_5abcbbb651de8' => '24/07/2018',
'field_5abcbbb851de9' => '15',
'field_5abcbbbb51dea' => 'yes'
]
]
];
foreach ($array as &$set) {
foreach ($set as &$subset) {
$subset = preg_replace('~^\d[1-9]/[1-9]\d{3}$~', '01/$0', $subset);
}
}
unset($set, $subset); // avoid future variable interferences
var_export($array);
Output:
array (
'field_5abcb693a68bc' =>
array (
0 =>
array (
'field_5abcbb1b51ddf' => 'mortgage',
'field_5ae58a0b58b58' => '',
'field_5abcbb1e51de0' => '10',
'field_5abcbb2051de1' => 'הידגלה',
'field_5abcbb2351de2' => '45,654,456',
'field_5abcbb6251de3' => '',
'field_5abcbb6651de4' => '01/04/2017',
'field_5abcbb6851de5' => '4,454,656',
'field_5abcbb6b51de6' => '24/07/2018',
'field_5abcbbb351de7' => '657',
'field_5abcbbb651de8' => '24/07/2018',
'field_5abcbbb851de9' => '15',
'field_5abcbbbb51dea' => 'yes',
),
),
)
You can anonymously process down the levels of the array without actually knowing any of the names of the keys like this for example
foreach ($arr as $key => &$outer) {
foreach ($outer as &$inner) {
foreach ($inner as $k => $v) {
if ( preg_match('/^\d[1-9]\/[1-9][0-9][0-9][0-9]$/',$v) ) {
$inner[$k] = '01/' . $v;
}
}
}
}

Storing the full location of an element in a multidimensional array for reuse

This question is based on my other question here about a suitable array processing algorithm.
In my case, I want to flatten a multidimensional array, but I need to store the full key to that element for reuse later.
For example :
array(
0 => array(
'label' => 'Item1',
'link' => 'http://google.com',
'children' => null
)
1 => array(
'label' => 'Item2',
'link' => 'http://google.com',
'children' => array( 3 => array(
'label' => 'SubmenuItem1',
'link' => 'http://www.yahoo.com',
'children' => null
)
)
)
2 => array(
'label' => 'Item3',
'link' => 'http://google.com',
'children' => null
)
)
Should be flattened into something like the following table
Key Link
===================================
[0] http://google.com
[1] http://google.com
[2] http://google.com
[1][3] http://yahoo.com
The problem is that I while I can easily store the location of an element in a multidimensional array, I am finding it to be quite hard to retrieve that element later. For example, if I store my key as $key = "[1][3]", I can not access it using $myarray[$key]. Is there anyway to do this?
Solution using recursion:
//Array parts should be an array containing the keys, for example, to address
//SubmenuItem1, I had 1.3 when the array was flattened. This was then exploded() to the array [1, 3]
$this->recurseIntoArray($myArray, $arrayParts);
private function recurseIntoArray(&$array, $arrayParts){
$current = $arrayParts[0];
$array[$current]['blah'] = 'blah'; //If you want to update everyone in the chain on the way down, do it here
array_shift($arrayParts);
if (!empty($arrayParts)){
$this->recurseIntoArray($array[$current]['children'], $arrayParts);
}else{
//If you want to update only the last one in the chain, do it here.
}
}

PHP / Mongo: how do you update nested data?

I've been playing around with Mongo for about a week now and I still can't work out how to modify nested arrays in Mongo with php.
So here is a sample document...
array (
'_id' => new MongoId("4cb30f560107ae9813000000"),
'email' => 'mo#maurice-campobasso.com',
'firstname' => 'Maurice',
'lastname' => 'Campobasso',
'password' => 'GOD',
'productions' =>
array (
0 =>
array (
'title' => 'a',
'date' => '1286811330.899',
),
1 =>
array (
'title' => 'b',
'date' => '1286811341.183',
),
2 =>
array (
'title' => 'c',
'date' => '1286811350.267',
),
3 =>
array (
'title' => 'd',
'date' => '1286811356.05',
),
),
)
What I wan't to do is delete an array inside the productions array, but I can't work out how. I've been playing with 'update('$pull' => ...etc)' but I haven't been able to make it work.
OK, there are a few ways to do this. In your case, I would do something like
mymongoobject.update( $unset : { "productions.2" : 1 } }
That's basically saying to unset the ".2" element of productions. Some docs here.
Now $pull should also work, but it's a little tougher because "productions" is actually an array of arrays (or objects with sub-objects). So you'd have to match arrays exactly:
mymongoobject.update( $pull : { "productions" : {'title':'d', 'date':'1286811356.05'} }
In the case above, the unset is probably the easiest option (though it will leave a "hole" in the array)
That is actually very easy, unlike traditional sql stuff you just modify the whole data and pass it back.
$cursor = $mongo->yourDB->yourCollection->findOne("_id",4cb30f560107ae9813000000);
//let's remove last item on productions
array_splice($cursor["productions"],2);
//and update the mongo document
echo $mongo->yourDB->yourCollection->update($cursor);
//it echoes 1 if successful
hope it helps.

Categories