Undefined offset Error when searching Array - php

I am searching an array for a known value wid to get the key which will then help me get the cid value.
$proximity = array(
'0' => array ('wid' => 4, 'cid' => 100),
'1' => array ('wid' => 1, 'cid' => 50),
'3' => array ('wid' => 2, 'cid' => 50)
);
$key = array_search(2, array_column($proximity, 'wid'));
print_r($key);
print_r($proximity[$key]['cid']);
When I search for wid 4 and 1 everything works great.
However when I search for wid: 2 I get Undefined offset: 2.
Why is this happening and how do I fix it?

Array_column returns values of field as usual indexed array, even if source array is associative. So the returned key is correct only when source array has no omitted indexes, and your search, in fact, gets "position" in array.
For example, for such an array
$proximity = array(
'a' => array ('wid' => 4, 'cid' => 100),
'b' => array ('wid' => 1, 'cid' => 50),
'c' => array ('wid' => 2, 'cid' => 50)
);
array_column will return
Array
(
[0] => 4
[1] => 1
[2] => 2
)
If you really want to search through array_column, to work around this problem and get item by that "position", use
print_r(array_slice($proximity, $key, 1)['cid']);
or
print_r(array_values($proximity)[$key]['cid']);

It's because when you are doing array_search() it is only searching the first level of the array, you can search like the following:
<?php
echo 'hello world';
$proximity = array(
'0' => array ('wid' => 4, 'cid' => 100),
'1' => array ('wid' => 1, 'cid' => 50),
'3' => array ('wid' => 2, 'cid' => 50)
);
foreach($proximity as $subarray){
$key = array_search(2, array_column($subarray, 'wid'));
echo print_r($key) . '<br />';
echo print_r($proximity[$key]['cid']) . '<br />';
}
?>
This searches each sub array that is in the main array, meaning it doesn't matter how many elements are in $proximity, it will search all of them.

array_column() is trashing your original keys. I don't think there is any shame in using a loop with a break. This is clean and fast and the gaps in the keys are no bother; in fact your original keys are preserved if you need them.
Code: (demo: https://3v4l.org/8XWcf )
$proximity = array(
'0' => array ('wid' => 4, 'cid' => 100),
'1' => array ('wid' => 1, 'cid' => 50),
'3' => array ('wid' => 2, 'cid' => 50)
);
$wid=2;
foreach($proximity as $i=>$a){
if($a['wid']==$wid){
echo "i=$i and cid={$a['cid']}";
break;
}
}
Output:
i=3 and cid=50
If you don't want control structures as iterators, this seems like a sensible alternative:
$wid=2;
$proximity=array_column($proximity,NULL,'wid');
if(isset($proximity[$wid])){
echo "cid={$proximity[$wid]['cid']}";
}else{
echo 'wid not found';
}
This assumes wid values are unique and uses the values as keys for the subarrays. Demo : https://3v4l.org/Ph1tH

Related

Merge the arrays

I have two arrays $array and $array2. I need to merge them on behalf of common key value i.e. entry_id.
Well I need to merge them is such a way that if the entry_id of array 1 matches with the entry_id of array2, it merges. If the entry_id doesn't match that array remains as it but it should be entered in the merged array. I have tried but i didn't get the desired results. If it is possible to do this without function?
Thanks in Advance.
Here is my code
<?php
$array = array(
array(
'title' => 'mytitleeee',
'entry_id' => 1000
),
array(
'title' => 'myt',
'entry_id' => 1001
),
array(
'title' => 'mytRRRR',
'entry_id' => 1003
),
array(
'title' => 'RUKES',
'entry_id' => 1004
)
);
$array2 = array(
array(
'author_id' => 'desc1',
'entry_id' => 1000
),
array(
'author_id' => 'desc2',
'entry_id' => 1001
),
array(
'author_id' => 'desc3',
'DAY' => 'MON',
'entry_id' => 1003
),
array(
'author_id' => 'desc7',
'DAY' => 'TUE',
'entry_id' => 1012
)
);
$x = array();
foreach($array as $value => $ans){
}
foreach($array2 as $value1 => $ans1){
}
if($ans1['entry_id']!= $ans['entry_id']){
$x = ($ans1);
echo"<pre>";
print_r($x);
}
You could apply this array_reduce call to the array_merge result:
$result = array_reduce(array_merge($array, $array2), function ($acc, $el) {
$key = $el['entry_id'];
$acc[$key] = isset($acc[$key]) ? $acc[$key] + $el : $el;
return $acc;
}, []);
$result will have the following for your sample data:
array (
1000 => array (
'title' => 'mytitleeee',
'entry_id' => 1000,
'author_id' => 'desc1',
),
1001 => array (
'title' => 'myt',
'entry_id' => 1001,
'author_id' => 'desc2',
),
1003 => array (
'title' => 'mytRRRR',
'entry_id' => 1003,
'author_id' => 'desc3',
'DAY' => 'MON',
),
1004 => array (
'title' => 'RUKES',
'entry_id' => 1004,
),
1012 => array (
'author_id' => 'desc7',
'DAY' => 'TUE',
'entry_id' => 1012,
),
)
How it works
First the two arrays are merged:
array_merge($array, $array2)
This just appends the elements of the second array after those of the first.
This array is then passed to array_reduce, which calls the callback function -- given as argument -- for each element.
Furthermore, that function also gets an accumulated value ($acc), which in the first call is [] (provided as final argument to reduce). Whatever the function returns becomes the accumulated value that is passed in the second function call (for the second element), ...etc. The final returned value becomes the return value of reduce.
So in this case the accumulated value is an associative array that is keyed by entry_id. If at a certain moment that key already exists, the current value is merged with the value that is already in $acc: this merge is done with the + operator. If the entry_id of the current element is not yet in $acc it is added to it.
This if...else is implemented with the ternary operator (... ? ... : ...).
The return$accstatement ensures that the the next time this callback is called (for the next element),$acc` is again that accumulated value.

PHP - Reorder array to match the order of another array

I have 1 array that has the right values that I need but it is out of order. I then have another array with the same keys and it is in the right order but the values are not what I need.
Here is my first array with the correct values but is out of order:
Array
(
[countTotal] => 7268
[zip] =>
[yearName] =>
[countZipRadius] =>
[Acura] => 1334
[Cadillac] => 511
[Ford] => 5423
)
Here is my second array with the right order but the wrong values:
Array
(
[countZipRadius] => 0
[zip] => 1
[yearName] => 2
[Acura] => 3
[Cadillac] => 4
[Ford] => 5
[countTotal] => 6
)
I am trying to figure out a way to create a new array with the right values from array 1 but that is in the order of array 2.
I have been playing with it for awhile and cannot seem to get it.
Any help would be great.
Thanks!
$c = array();
foreach (array_keys($b) as $k) {
$c[k] = $a[k];
}
You could use php's array_multisort function:
$original = array(
'countTotal' => 7268,
'zip' => '',
'yearName' => '',
'countZipRadius' => '',
'Acura' => 1334,
'Cadillac' => 511,
'Ford' => 5423,
);
$right = array(
'countZipRadius' => 0,
'zip' => 1,
'yearName' => 2,
'Acura' => 3,
'Cadilac' => 4,
'Ford' => 5,
'countTotal' => 6
);
//make sure both arrays are in the same order
ksort($original);
ksort($right);
array_multisort($right, $original);
print_r($original);
When you give it two arrays with the same number of elements it sorts both arrays, based on the order of the first array - in this case the 0, 1, 2, 3, etc. values in $right
Create a New Array (Array C)
Use a FOR loop to go through Array B
For each value in Array B, get the value with the same key from Array A and set Array C append those values to Array C. This will put them in the correct order in C.
Using scones' method:
$original = array(
'countTotal' => 7268,
'zip' => '',
'yearName' => '',
'countZipRadius' => '',
'Acura' => 1334,
'Cadillac' => 511,
'Ford' => 5423,
);
$right = array(
'countZipRadius' => 0,
'zip' => 1,
'yearName' => 2,
'Acura' => 3,
'Cadilac' => 4,
'Ford' => 5,
'countTotal' => 6
);
foreach ($right as $key => $value) {
$new[$key] = $original[$key];
}
print_r($new);
$array = array('a' => 100, 'b' => '5');
$newArray = array_combine(array_keys($array), range(0, count($array) - 1));
var_dump($newArray);

Displaying an array inside an array?

I have an array inside an array and I'd like to simply print out the contents of it... the problem is what I'm trying doesn't work... ie
foreach($retval as $k=>$v){
if (is_array($v)){
foreach($v as $l=>$w){
echo $l . ' = ' . $w . '<br />';
}
} else {
echo $k . ' = ' . $v . '<br />';
}
Doing that however I end up with:
id = 2
name = Speakers
form_field = hidden
display_order = 0
groups = Array
So I'm not getting a foreach in that inside array.. what am I doing wrong? It seems actually that my code believes everything return is an array when I'm pretty sure that only 'groups' is an array.
the structure of the array looks like so:
array ( 0 => array ( 'id' => 2, 'name' => 'Speakers', 'form_field' => 'hidden', 'display_order' => '0', 'groups' => array ( 0 => array ( 'bit' => '1', 'name' => 'don', 'display_order' => '4', 'subscribers' => 8, ), 1 => array ( 'bit' => '2', 'name' => 'tyler', 'display_order' => '5', 'subscribers' => 0, ), 2 => array ( 'bit' => '4', 'name' => 'stephen', 'display_order' => '6', 'subscribers' => 0, ), 3 => array ( 'bit' => '8', 'name' => 'daniel', 'display_order' => '7', 'subscribers' => 0, ), 4 => array ( 'bit' => '16', 'name' => 'william', 'display_order' => '8', 'subscribers' => 0, ), 5 => array ( 'bit' => '32', 'name' => 'bobbys', 'display_order' => '9', 'subscribers' => 0, ), ), ), )
Long story short, I'm actually just trying to search this whole thing for say the name 'bobby' and get a simple true or false on whether that value exists anywhere in there.
print_r($myArray);
PHP Manual
<?php
$a = array ('a' => 'apple', 'b' => 'banana', 'c' => array ('x', 'y', 'z'));
print_r ($a);
?>
would give:
Array
(
[a] => apple
[b] => banana
[c] => Array
(
[0] => x
[1] => y
[2] => z
)
)
Not sure if this is what you are looking for...
print_r() gives you a visual representation while var_export() returns valid, executable php code. Manual: var_export()
You're assuming that arrays are only doubly-nested, when $retval[<something>]['groups'] is also an array. Use recursion to handle this instead of just adding levels upon levels.
It sounds like you need to reconsider what you are trying to do.
If you just want to see what is in your array so that you know how to get at a particular piece of data, then you're probabaly after print_r, var_export or similar as mentioned above.
print_r($retval);
If you want your php script to be able to work out on it's own whether 'bobby' is in the array, then you might have some more information that will help your search. For example, do you know the structure of your array and that you're searching for a name? If so, then you only need to check the strings that are in $array[$foo]['name']. You could adapt your code like so:
foreach($retval as $k=>$v) {
if ($v['name'] == 'bobby') {
echo "Bobby is at index $k";
}
}
PHP contains lots of functions for arrays, although these tend to be for single-dimension arrays.
P.S. Please edit the structure of your array to make it easier to read.
If your goal is to understand if a value is in any nested array you can do this:
foreach($retval as $vec){
if(in_array("bobby", $vec)
do something
Use a RecursiveArrayIterator wrapped in RecursiveIteratorIterator. The syntax will then be:
$arr = array('this is your complicated multi-dimensional array');
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($arr));
foreach($iterator as $key => $value){
echo '['.$key.'] => '.$value.'<br />';
}
You can even use $iterator->depth() to determine the depth of a current element.

PHP: merge two arrays while keeping keys instead of reindexing?

How can I merge two arrays (one with string => value pairs and another with int => value pairs) while keeping the string/int keys? None of them will ever overlap (because one has only strings and the other has only integers).
Here is my current code (which doesn't work, because array_merge is re-indexing the array with integer keys):
// get all id vars by combining the static and dynamic
$staticIdentifications = array(
Users::userID => "USERID",
Users::username => "USERNAME"
);
// get the dynamic vars, formatted: varID => varName
$companyVarIdentifications = CompanyVars::getIdentificationVarsFriendly($_SESSION['companyID']);
// merge the static and dynamic vars (*** BUT KEEP THE INT INDICES ***)
$idVars = array_merge($staticIdentifications, $companyVarIdentifications);
You can simply 'add' the arrays:
>> $a = array(1, 2, 3);
array (
0 => 1,
1 => 2,
2 => 3,
)
>> $b = array("a" => 1, "b" => 2, "c" => 3)
array (
'a' => 1,
'b' => 2,
'c' => 3,
)
>> $a + $b
array (
0 => 1,
1 => 2,
2 => 3,
'a' => 1,
'b' => 2,
'c' => 3,
)
Considering that you have
$replaced = array('1' => 'value1', '4' => 'value4');
$replacement = array('4' => 'value2', '6' => 'value3');
Doing $merge = $replacement + $replaced; will output:
Array('4' => 'value2', '6' => 'value3', '1' => 'value1');
The first array from sum will have values in the final output.
Doing $merge = $replaced + $replacement; will output:
Array('1' => 'value1', '4' => 'value4', '6' => 'value3');
I just want to add another possibility of doing a merge while keeping keys.
Besides adding key/values to existing arrays using the + sign you could do an array_replace.
$a = array('foo' => 'bar', 'some' => 'string', 'me' => 'is original');
$b = array(42 => 'answer to the life and everything', 1337 => 'leet', 'me' => 'is overridden');
$merged = array_replace($a, $b);
The result will be:
Array
(
[foo] => bar
[some] => string
[me] => is overridden
[42] => answer to the life and everything
[1337] => leet
)
Same keys will be overwritten by the latter array.
There is also an array_replace_recursive, which do this for subarrays, too.
Live example on 3v4l.org
Two arrays can be easily added or union without chaning their original indexing by + operator. This will be very help full in laravel and codeigniter select dropdown.
$empty_option = array(
''=>'Select Option'
);
$option_list = array(
1=>'Red',
2=>'White',
3=>'Green',
);
$arr_option = $empty_option + $option_list;
Output will be :
$arr_option = array(
''=>'Select Option'
1=>'Red',
2=>'White',
3=>'Green',
);
The OP.'s requirement is to preserve keys (keep keys) and not overlap (I think overwrite). In some cases such as numeric keys it is possible but if string keys it seems to be not possible.
If you use array_merge() the numeric keys will always re-index or renumbered.
If you use array_replace(), array_replace_recursive() it will be overlap or overwrite from the right to the left. The value with the same key on first array will be replaced with second array.
If you use $array1 + $array2 as the comment was mentioned, if the keys are same then it will keep the value from first array but drop the second array.
Custom function.
Here is my function that I just wrote to work on the same requirements. You are free to use for any purpose.
/**
* Array custom merge. Preserve indexed array key (numbers) but overwrite string key (same as PHP's `array_merge()` function).
*
* If the another array key is string, it will be overwrite the first array.<br>
* If the another array key is integer, it will be add to first array depend on duplicated key or not.
* If it is not duplicate key with the first, the key will be preserve and add to the first array.
* If it is duplicated then it will be re-index the number append to the first array.
*
* #param array $array1 The first array is main array.
* #param array ...$arrays The another arrays to merge with the first.
* #return array Return merged array.
*/
function arrayCustomMerge(array $array1, array ...$arrays): array
{
foreach ($arrays as $additionalArray) {
foreach ($additionalArray as $key => $item) {
if (is_string($key)) {
// if associative array.
// item on the right will always overwrite on the left.
$array1[$key] = $item;
} elseif (is_int($key) && !array_key_exists($key, $array1)) {
// if key is number. this should be indexed array.
// and if array 1 is not already has this key.
// add this array with the key preserved to array 1.
$array1[$key] = $item;
} else {
// if anything else...
// get all keys from array 1 (numbers only).
$array1Keys = array_filter(array_keys($array1), 'is_int');
// next key index = get max array key number + 1.
$nextKeyIndex = (intval(max($array1Keys)) + 1);
unset($array1Keys);
// set array with the next key index.
$array1[$nextKeyIndex] = $item;
unset($nextKeyIndex);
}
}// endforeach; $additionalArray
unset($item, $key);
}// endforeach;
unset($additionalArray);
return $array1;
}// arrayCustomMerge
Testing.
<?php
$array1 = [
'cat',
'bear',
'fruitred' => 'apple',
3 => 'dog',
null => 'null',
];
$array2 = [
1 => 'polar bear',
20 => 'monkey',
'fruitred' => 'strawberry',
'fruityellow' => 'banana',
null => 'another null',
];
// require `arrayCustomMerge()` function here.
function printDebug($message)
{
echo '<pre>';
print_r($message);
echo '</pre>' . PHP_EOL;
}
echo 'array1: <br>';
printDebug($array1);
echo 'array2: <br>';
printDebug($array2);
echo PHP_EOL . '<hr>' . PHP_EOL . PHP_EOL;
echo 'arrayCustomMerge:<br>';
$merged = arrayCustomMerge($array1, $array2);
printDebug($merged);
assert($merged[0] == 'cat', 'array key 0 should be \'cat\'');
assert($merged[1] == 'bear', 'array key 1 should be \'bear\'');
assert($merged['fruitred'] == 'strawberry', 'array key \'fruitred\' should be \'strawberry\'');
assert($merged[3] == 'dog', 'array key 3 should be \'dog\'');
assert(array_search('another null', $merged) !== false, '\'another null\' should be merged.');
assert(array_search('polar bear', $merged) !== false, '\'polar bear\' should be merged.');
assert($merged[20] == 'monkey', 'array key 20 should be \'monkey\'');
assert($merged['fruityellow'] == 'banana', 'array key \'fruityellow\' should be \'banana\'');
The results.
array1:
Array
(
[0] => cat
[1] => bear
[fruitred] => apple
[3] => dog
[] => null
)
array2:
Array
(
[1] => polar bear
[20] => monkey
[fruitred] => strawberry
[fruityellow] => banana
[] => another null
)
---
arrayCustomMerge:
Array
(
[0] => cat
[1] => bear
[fruitred] => strawberry
[3] => dog
[] => another null
[4] => polar bear
[20] => monkey
[fruityellow] => banana
)
Try array_replace_recursive or array_replace functions
$a = array('userID' => 1, 'username'=> 2);
array (
userID => 1,
username => 2
)
$b = array('userID' => 1, 'companyID' => 3);
array (
'userID' => 1,
'companyID' => 3
)
$c = array_replace_recursive($a,$b);
array (
userID => 1,
username => 2,
companyID => 3
)
http://php.net/manual/en/function.array-replace-recursive.php

Find all second level keys in multi-dimensional array in php

I want to generate a list of the second level of keys used. Each record does not contain all of the same keys. But I need to know what all of the keys are. array_keys() doesn't work, it only returns a list of numbers.
Essentially the output Im looking for is:
action, id, validate, Base, Ebase, Ftype, Qty, Type, Label, Unit
I have a large multi-dimensional array that follows the format:
Array
(
[0] => Array
(
[action] => A
[id] => 1
[validate] => yes
[Base] => Array
(
[id] => 2945
)
[EBase] => Array
(
[id] => 398
)
[Qty] => 1
[Type] => Array
(
[id] => 12027
)
[Label] => asfhjaflksdkfhalsdfasdfasdf
[Unit] => asdfas
)
[1] => Array
(
[action] => A
[id] => 2
[validate] => yes
[Base] => Array
(
[id] => 1986
)
[FType] => Array
(
[id] => 6
)
[Qty] => 1
[Type] => Array
(
[id] => 13835
)
[Label] => asdssdasasdf
[Unit] => asdger
)
)
Thanks for the help!
<?php
// Gets a list of all the 2nd-level keys in the array
function getL2Keys($array)
{
$result = array();
foreach($array as $sub) {
$result = array_merge($result, $sub);
}
return array_keys($result);
}
?>
edit: removed superfluous array_reverse() function
array_keys(call_user_func_array('array_merge', $a));
Merge all values and retrieve the resulting keys.
One liner:
$keys=array_unique(array_reduce(array_map('array_keys',$data),'array_merge',[]));
Or in a function:
function get_array_children_keys($data) {
return array_unique(
array_reduce(array_map('array_keys', $data), 'array_merge', [])
);
}
Now lets break this down with an example, here is some sample data:
[
['key1' => 0],
['key1' => 0, 'key2' => 0],
['key3' => 0]
]
Starting with the inner most function, we run array_map with the array_keys function:
array_map('array_keys', $data)
This gives us the keys of from all child arrays
[
['key1'],
['key1', 'key2'],
['key3']
]
Then we run the array_reduce on the data with the array_merge callback and an empty array as the initial value:
array_reduce(..., 'array_merge', []);
This converts our multiple arrays into 1 flat array:
[
'key1',
'key1',
'key2',
'key3'
]
Now we strip out our duplicates with array_unique:
array_unique(...)
And end up with all our keys:
[
'key1',
'key2',
'key3'
]
foreach($bigArray as $array){
foreach($array as $key=>$value){
echo $key;
}
}
That should do what you want.
What about something like this :
$your_keys = array_keys($your_array[0]);
Of course, this is considering all sub-arrays have the same keys ; in this case, you only need the keys of the first sub-array (no need to iterate over all first-level sub-arrays, I guess)
And, as a shortened / simplified example :
$your_array = array(
array(
'action' => 'A',
'id' => 1,
'base' => array('id' => 145),
),
array(
'action' => 'B',
'id' => 2,
'base' => array('id' => 145),
),
array(
'action' => 'C',
'id' => 3,
'base' => array('id' => 145),
)
);
$your_keys = array_keys($your_array[0]);
var_dump($your_keys);
Will get you :
array
0 => string 'action' (length=6)
1 => string 'id' (length=2)
2 => string 'base' (length=4)
You can the use implode to get the string you asked for :
echo implode(', ', $your_keys);
will get you :
action, id, base
ie, the list of the keys of the first sub-array.
function __getAll2Keys($array_val){
$result = array();
$firstKeys = array_keys($array_val);
for($i=0;$i<count($firstKeys);$i++){
$key = $firstKeys[$i];
$result = array_merge($result,array_keys($array_val[$key]));
}
return $result;
}
try this function. It will return as you want.
While #raise answers provides a shortcut, it fails with numeric keys. The following should resolve this:
$secondKeys=array_unique(call_user_func_array('array_merge', array_map('array_keys',$a)));
array_map('array_keys',$a) : Loop through while getting the keys
...'array_merge'... : Merge the keys array
array_unique(... : (optional) Get unique keys.
I hope it helps someone.
UPDATE:
Alternatively you can use
$secondKeys=array_unique(array_merge(...array_map('array_keys', $a)));
That provides same answer as above, and much faster.
My proposal, similar to this answer but faster and using spread operator (PHP 5.6+).
array_merge(...array_values($fields))
if you want move names to array values and reset keys to 0..n just use array_keys in last step.
array_keys(array_merge(...array_values($fields)))
Maybe you can use array_map function, which allows you to avoid array iteration and return an array with the keys you need as values.
will be like this
$newArray = array_map(function($value){return array_keys($value);},$yourArray);
var_dump($newArray);
array (size=2)
0 =>
array (size=9)
0 => string 'action' (length=6)
1 => string 'id' (length=2)
2 => string 'validate' (length=8)
3 => string 'Base' (length=4)
4 => string 'EBase' (length=5)
5 => string 'Qty' (length=3)
6 => string 'Type' (length=4)
7 => string 'Label' (length=5)
8 => string 'Unit' (length=4)
1 =>
array (size=9)
0 => string 'action' (length=6)
1 => string 'id' (length=2)
2 => string 'validate' (length=8)
3 => string 'Base' (length=4)
4 => string 'FType' (length=5)
5 => string 'Qty' (length=3)
6 => string 'Type' (length=4)
7 => string 'Label' (length=5)
8 => string 'Unit' (length=4)
With this function you can get all keys from a multidimensional array
function arrayKeys($array, &$keys = array()) {
foreach ($array as $key => $value) {
$keys[] = $key;
if (is_array($value)) {
$this->arrayKeys($value, $keys);
}
}
return $keys;
}
Only if all records have the same keys you could do:
$firstItem = reset($array);
$keys = array_keys($firstItem);
Obviously, this is not the correct answer to this specific question, where the records have different keys. But this might be the question you find when looking how to retrieve second level keys from an array where all keys are the same (I did). If all the record have the same keys, you can simply use the first item in the array with reset() and get the keys from the first item with array_keys().

Categories