Obtain key from array through value - php

How can I obtain a key in a array just by knowing it's value? For example, here is an array:
$array = Array("Item1" => array("Number" => "One", "Letter" => "A"));
Just by knowing "One" or "A", how can I get the main key name, Item1?
I've looked into array_key_value and in_array but I do not think that those functions are helpful for my kind of array.

Since it is a 2d array, you will want to search the inner array for the value so you would have to make your own function to do this. Something like this:
function findInArray($array, $lookup){
//loop over the outer array getting each key and value.
foreach($array as $key=>$value){
//if we found our lookup value in the inner array
if(in_array($lookup, $value)){
//return the original key
return $key;
}
}
//else, return null because not found
return null;
}
$array = Array("Item1" => array("Number" => "One", "Letter" => "A"));
var_dump(findInArray($array, 'One')); //outputs string(5) "Item1"
var_dump(findInArray($array, 'Two')); //outputs null
Demo: https://3v4l.org/oRjHK

This function may help you
function key_of_value($array, $value){
foreach($array as $key=>$val){
if(in_array($value, $val)){
return $key;
}
}
return null;
}
echo key_of_value(['Item1'=>['One','Two','Three','Hello',2,6]],'A');

There is no way around iterating through your data. This might be a little more elegant than two foreach loops:
<?php
$match = null;
$needle = 'Two';
$haystack = [
'Item1' => [
'Number' => 'One',
'Letter' => 'A'
],
'Item2' => [
'Number' => 'Two',
'Letter' => 'B'
],
'Item3' => [
'Number' => 'Three',
'Letter' => 'C'
],
];
array_walk($haystack, function($entry, $key) use ($needle, &$match) {
if(in_array($needle, $entry)) {
$match = $key;
}
});
var_dump($match);
The output obviously is:
string(5) "Item2"

You can use array_walk_recursive to iterate on array values recursive. I write a function that return main key of searched value in nested arrays.
<?php
$array = array("Item1" => array("Number" => "One", "Letter" => "A", 'other' => array('Number' => "Two")));
echo find_main_key($array, 'One'); //Output: "Item1"
echo find_main_key($array, 'A'); //Output: "Item1"
echo find_main_key($array, 'Two'); //Output: "Item1"
var_dump(find_main_key($array, 'nothing')); // NULL
function find_main_key($array, $value) {
$finded_key = NULL;
foreach($array as $this_main_key => $array_item) {
if(!$finded_key) {
array_walk_recursive($array_item, function($inner_item, $inner_key) use ($value, $this_main_key, &$finded_key){
if($inner_item === $value) {
$finded_key = $this_main_key;
return;
}
});
}
}
return $finded_key;
}

This is how I would do it:
foreach($array as $key => $value) {
if(in_array('One', $value)) echo $key;
}

Related

Get key (not index) from qualifying row in an associative array of associative arrays

Here my array:
$array = [
'key1' => [
'first' => 'azerty',
'second' => 'qwerty'
],
'key2' => [
'first' => 'hello',
'second' => 'world'
]
];
With the value 'qwerty' I would like to retrieve the 'key1'.
I looking for something like that:
$theKeyIWant = array_search('qwerty', array_column($array, 'second'));
But I get '0', instead of 'key1' (and I know that's how it works)
Anyone know how to adapt this code or know another code to get the key value?
Slight modification to your code to combine the keys and column values:
$theKeyIWant = array_search('qwerty', array_combine(array_keys($array), array_column($array, 'second')));
The problem with seeking "something sexier" for this task is that if "sexier" means a "functional iterator", then that comes a cost of not being able to "return early" (doing unnecessary cycles).
If you want a single-line function to call, you can build your own and put it in a helpers file somewhere in your project. My strong advice is to abandon "sexy" for this task and use a breakable foreach loop.
Code: (Demo)
function getRowKey($array, $column, $value) {
foreach ($array as $key => $row) {
if ($row[$column] === $value) {
return $key;
}
}
return null;
}
var_export(getRowKey($array, 'second', 'qwerty'));
If you are going to perform repeated searches on the same array and the second column is guaranteed to contain unique values, then you can convert the array into a lookup array without losing any data. (Demo)
function restructure($array, $columnToKey) {
$result = [];
foreach ($array as $key => $row) {
$result[$row[$columnToKey]] = $row + ['oldKey' => $key];
}
return $result;
}
var_export(restructure($array, 'second')['qwerty']);
To solve this is to loop through the outer array and use array_search() to search for the value within each inner array.
$value = 'qwerty';
$theKeyIWant = null;
foreach ($array as $key => $innerArray) {
if (array_search($value, $innerArray) !== false) {
$theKeyIWant = $key;
break;
}
}
echo $theKeyIWant; // Output: key1
array_keys returns an array of an array's keys.
<?php
$array = [
'key1' => [
'first' => 'azerty',
'second' => 'qwerty'
],
'key2' => [
'first' => 'hello',
'second' => 'world'
]
];
$theKeyIWant = array_search('qwerty', array_column($array, 'second'));
echo array_keys($array)[$theKeyIWant];
?>
3V4l

Find elements with empty value in multidimensional array

I have an array like the below:
$arrays = [
'a' => [
'name' => "Name 1",
'age' => "99",
'add' => ""
],
'b' => [
'name' => "Name 2",
'age' => "99",
'add' => "Add2"
],
'c' => [
'name' => "Name 3",
'age' => "99",
'add' => "Add3"
],
'd' => [
'name' => "",
'age' => "",
'add' => "Add4"
]
];
I want to get a result like:
$res = [
'a' => ['add'],
'd' => ['name','age']
];
I have tried with the below code, but it returns 1.
$status = array_walk_recursive($arrays, function($v, $k) {
global $output;
if (empty($v) && $v !== 0)
$output[$k] = $v;
});
I want to do it without using any loops because my real input array is very large and I am concerned with performance.
If your input is always of a fixed depth, you can map the existing values to the keys of all empty items:
$output = array_map(function($row) {
return array_keys(array_filter($row, function ($e) {
return empty($e) && $e !== 0;
}));
}, $arrays);
The outer function runs for each "row", the value of which is then converted into a list of all keys with empty values (excluding zeroes, as in the question).
This will keep the outer keys B & C as empty arrays, so if you want them to be removed as well then run another iteration of array_filter over the result:
$output = array_filter($output)
See https://3v4l.org/c23ZB
As mentioned in the comments, there are still several loops going on here, they're just not as visible in the code. A regular foreach loop might end up being a lot easier to read, and possibly perform faster as well.
You can use next combination of array_walk & array_filter:
$result = [];
array_walk(
$arrays,
function($el, $key) use(&$result) {
$empty = array_filter($el, function($el){return $el == "";});
$empty_keys = array_keys($empty);
if (count($empty_keys)) $result[$key] = $empty_keys;
}
);
Try it here
This is another way to achieve your desired output.
$result = [];
foreach($arrays as $key => $value) {
$empty_arr = array_filter($value, function ($ele) {
return empty($ele);
});
$empty_arr_keys = array_keys($empty_arr);
if(!empty($empty_arr_keys)) $result[$key] = $empty_arr_keys;
}
print_r($result);
#iainn's answer can be sharpened up by calling !strlen() on the deep values.
Code: (Demo)
var_export(
array_filter(
array_map(
fn($row) => array_keys(
array_filter(
$row,
fn($v) => !strlen($v)
)
),
$array
)
)
);
But you will end up making fewer iterations and writing cleaner, more intuitive/readable code if you use classic loops. This is how I would write it in my own project:
Code: (Demo)
$result = [];
foreach ($array as $rowKey => $row) {
foreach ($row as $key => $value) {
if (!strlen($value)) {
$result[$rowKey][] = $key;
}
}
}
var_export($result);

How to combine two different multi dimensional arrays (PHP)

I want to combine two different multi-dimensional arrays, with one providing the correct structure (keys) and the other one the data to fill it (values).
Notice that I can't control how the arrays are formed, the structure might vary in different situations.
$structure = [
"a",
"b" => [
"b1",
"b2" => [
"b21",
"b22"
]
]
];
$data = [A, B1, B21, B22];
Expected result:
$array = [
"a" => "A",
"b" => [
"b1" => "B1",
"b2" => [
"b21" => "B21",
"b22" => "B22"
]
]
];
You can use the following code, however it will only work if number of elements in $data is same or more than $structure.
$filled = 0;
array_walk_recursive ($structure, function (&$val) use (&$filled, $data) {
$val = array( $val => $data[ $filled ] );
$filled++;
});
print_r( $structure );
Here is a working demo
You can try by a recursive way. Write a recursive method which takes an array as first argument to alter and the data set as its second argument. This method itself call when any array element is another array, else it alters the key and value with the help of data set.
$structure = [
"a",
"b" => [
"b1",
"b2" => [
"b21",
"b22"
]
]
];
$data = ['A', 'B1', 'B21', 'B22'];
function alterKey(&$arr, $data) {
foreach ($arr as $key => $val) {
if (!is_array($val)) {
$data_key = array_search(strtoupper($val), $data);
$arr[$val] = $data[$data_key];
unset($arr[$key]);
} else {
$arr[$key] = alterKey($val, $data);
}
}
ksort($arr);
return $arr;
}
alterKey($structure, $data);
echo '<pre>', print_r($structure);
Working demo.
This should work.
$structure = [
"a",
"b" => [
"b1",
"b2" => [
"b21",
"b22"
]
]
];
$new_structure = array();
foreach($structure as $key =>$value)
{
if(!is_array($value))
{
$new_structure[$value]= $value;
}else{
foreach($value as $k =>$v)
{
if(!is_array($v))
{
$new_structure[$key][$v]=$v;
}else
{
foreach($v as $kk => $vv)
{
$new_structure[$k][$vv]=$vv;
}
}
}
}
}
print_r($new_structure);exit;
Use
$array=array_merge($structure,$data);
for more information follow this link
how to join two multidimensional arrays in php

Is there better way to split array by key starts with certain string?

I have array for e.g.
$myArray = [
'id' => 1,
'code' => '1234',
'translation_lang_id' => 3,
'translation_name' => 'Lorem Ipsum',
'translation_description' => 'My content'
];
Now I need to split it into: first with all keys & values where key starts with translation_ and second with rest so it should finally looks like this:
$translationArray = [
'translation_lang_id' => 3,
'translation_name' => 'Lorem Ipsum',
'translation_description' => 'My content'
];
$baseData = [
'id' => 1,
'code' => '1234',
];
Is there better way to do this than loop?
You can use array_filter with the ARRAY_FILTER_USE_KEY flag to separate the different elements according to whether the key starts with 'translation_' or not:
$translationArray = array_filter($myArray,
function ($k) {
return substr($k, 0, 12) == 'translation_';
}, ARRAY_FILTER_USE_KEY);
$baseData = array_filter($myArray,
function ($k) {
return substr($k, 0, 12) != 'translation_';
}, ARRAY_FILTER_USE_KEY);
var_export($translationArray);
var_export($baseData);
Output:
array (
'translation_lang_id' => 3,
'translation_name' => 'Lorem Ipsum',
'translation_description' => 'My content',
)
array (
'id' => 1,
'code' => '1234',
)
Demo on 3v4l.org
One brute force approach would be to just iterate your array, and assign elements to the appropriate destination array:
$translationArray = array();
$baseData = array();
foreach ($myArray as $key => $value) {
if (preg_match("/^translation_/", $key)) {
$translationArray[$key] = $value;
}
else {
$baseData[$key] = $value;
}
}
Not a efficient method but it just for the fun of it.
Here's a one liner :-)
$baseData = array_diff_key($myArray, $translationArray = array_intersect_key($myArray,array_flip(preg_grep("/^translation/", array_keys($myArray)))));
It uses preg_grep on the keys then matches them with array_intersect from the main array.
$baseData is then created as an array_diff_key from $translationArray.
https://3v4l.org/HE5vK
Demo Link.
Search for any string replacing it with str and get the data in parts,
$str = "translation_";
$len = strlen($str); // upto length for fetching sub string
$translationArray = $baseData = [];
foreach ($input as $key => $value) {
if (substr($key, 0, $len) == $str) { // checking here
$translationArray[$key] = $value;
} else {
$baseData[$key] = $value;
}
}
You could pluck out the key values you want for one, and then difference the original array to get the other.
<?php
$input = [
'id' => 1,
'code' => '1234',
'translation_lang_id' => 3,
'translation_name' => 'Lorem Ipsum',
'translation_description' => 'My content'
];
$translation = array_filter($input, function($k) {
return strpos($k, 'translation_') === 0;
}, ARRAY_FILTER_USE_KEY);
$base = array_diff_key($input, $translation);
var_dump($translation, $base);
Output:
array(3) {
["translation_lang_id"]=>
int(3)
["translation_name"]=>
string(11) "Lorem Ipsum"
["translation_description"]=>
string(10) "My content"
}
array(2) {
["id"]=>
int(1)
["code"]=>
string(4) "1234"
}
But a loop is probably easier to read and follow:
foreach($input as $k=>$v)
strpos($k, 'translation_') === 0
? $translation[$k]=$v
: $base[$k]=$v;

php - find array value that has pattern index

I have an array like :
$a =['main'=>
[
'a' => ['1st'],
'b' => ['2nd'],
'c' => ['3th']
];
and I want do like:
if(in_array('1st', $a['main'][x])){
...
}
I need x(now it is a) value too
$resulting_keys = [];
foreach($a['main'] as $key => $value) {
if(in_array('1st', $value)) {
$resulting_keys[] = $key;
}
}
here are working example:
$a = array(
'main'=> array(
'a' => '1st',
'b' => '2nd',
'c' => '3th'
)
);
if(in_array('1st', $a['main'])){
echo 'Yes';
}else{
echo 'No';
}
Maybe try this:
array_filter($a['main'], function($el) {
return in_array('1st', $el);
})
Array filter function is a good solution to filter arrays
http://php.net/manual/en/function.array-filter.php

Categories