PHP array key exists from string - php

I have an array:
<?php
$array = [
'fruits' => [
'apple' => 'value',
'orange' => 'value'
],
'vegetables' => [
'onion' => 'value',
'carrot' => 'value'
];
I also have a string:
$string = 'fruits[orange]';
Is there any way to check if the - array key specified in the string - exists in the array?
For example:
<?php
if(array_key_exists($string, $array))
{
echo 'Orange exists';
}

Try this one. Here we are using foreach and isset function.
Note: This solution will also work for more deeper levels Ex: fruits[orange][x][y]
Try this code snippet here
<?php
ini_set('display_errors', 1);
$array = [
'fruits' => [
'apple' => 'value',
'orange' => 'value'
],
'vegetables' => [
'onion' => 'value',
'carrot' => 'value'
]
];
$string = 'fruits[orange]';
$keys=preg_split("/\[|\]/", $string, -1, PREG_SPLIT_NO_EMPTY);
echo nestedIsset($array,$keys);
function nestedIsset($array,$keys)
{
foreach($keys as $key)
{
if(array_key_exists($key,$array))://checking for a key
$array=$array[$key];
else:
return false;//returning false if any of the key is not set
endif;
}
return true;//returning true as all are set.
}

It would be a lot easier to check the other way around. As in check if the key is in the string. Since keys are unique, there's no way you have duplicates.
$array = [
'fruits' => [
'apple' => 'value',
'orange' => 'value'
],
'vegetables' => [
'onion' => 'value',
'carrot' => 'value'
]
];
$string = 'fruits[orange]';
$keys = array_keys($array['fruits']);
foreach($keys as $fruit) {
if(false !== stripos($string, $fruit)) {
return true;
}
}
While this solution is not necessarily ideal, the problem to begin with isn't exactly common.

You can walk recursively:
$array = [
'fruits' => [
'apple' => 'value',
'orange' => 'value'
],
'vegetables' => [
'onion' => 'value',
'carrot' => 'value'
]
];
$exists = false;
$search = "orange";
array_walk_recursive($array, function ($val, $key) use (&$exists,$search) {
if ($search === $key) { $exists = true; }
});
echo ($exists?"Exists":"Doesn't exist");
Prints:
Exists
Example: http://sandbox.onlinephpfunctions.com/code/a3ffe7df25037476979f4b988c2f36f35742c217

Instead of using regex or strpos like the other answers, you could also simply split your $string on [ and resolve the keys one by one until there's only one key left. Then use that last key in combination with array_key_exists() to check for your item.
This should work for any amount of dimensions (eg fruit[apple][value][1]).
Example:
<?php
$arr = [
'fruits' => [
'orange' => 'value'
]
];
// Resolve keys by splitting on '[' and removing ']' from the results
$keys = 'fruits[orange]';
$keys = explode("[", $keys);
$keys = array_map(function($s) {
return str_replace("]", "", $s);
}, $keys);
// Resolve item.
// Stop before the last key.
$item = $arr;
for($i = 0; $i < count($keys) - 1; $i++) {
$item = $item[$keys[$i]];
}
// Check if the last remaining key exists.
if(array_key_exists($keys[count($keys)-1], $item)) {
// do things
}

You can explode and check the indices of the array.
$array = array(
'fruits' => [
'apple' => 'value',
'orange' => 'value'
],
'vegetables' => [
'onion' => 'value',
'carrot' => 'value'
]);
$string = 'fruits[orange]';
$indexes = (preg_split( "/(\[|\])/", $string));
$first_index= $indexes[0];
$seconnd_index= $indexes[1];
if(isset($array[$first_index][$seconnd_index]))
{
echo "exist";
}
else
{
echo "not exist";
}
DEMO

Related

How can I get a value from an array by a child array value?

I've a huge problem. Somehow I need to get the variation_id from an array based on a value of a child array:
$array = [
[
'attributes' => [
'attribute_art-der-karte' => 'Rot'
],
'variation_id' => '222'
],
[
'attributes' => [
'attribute_art-der-karte' => 'Green'
],
'variation_id' => '221'
]
];
So in my case I've two things available:
The key attribute_art-der-karte
The value Rot
I found nothing here instead of a sorting. Any idea? Thanks!
Simply loop over the array and return the variation ID when your condition is met (an attribute exists with the given key and the given value):
function findVariationId(array $array, string $attrName, string $attrValue): ?string {
foreach ($array as $entry) {
if (($entry['attributes'][$attrName] ?? null) === $attrValue) {
return $entry['variation_id'];
}
}
return null;
}
Demo
You can also use array filter for this
<?php
$array = [
[
'attributes' => [
'attribute_art-der-karte' => 'Rot'
],
'variation_id' => '222'
],
[
'attributes' => [
'attribute_art-der-karte' => 'Green'
],
'variation_id' => '221'
]
];
function findByAttribute ($arr, $value) {
$result = array_filter($arr, function($elem) use($value){
return $elem['attributes']['attribute_art-der-karte'] == $value;
});
if ($result) {
return array_shift($result)['variation_id'];
}
return '';
}
var_dump(findByAttribute($array, 'Rot')); // gives '222'
var_dump(findByAttribute($array, 'a')); // returns ''
var_dump(findByAttribute($array, 'Green')); // gives 221
An additional option using array_search() and array_column():
<?php
$array = [
['attributes' => ['attribute_art-der-karte' => 'Rot'], 'variation_id' => '222'],
['attributes' => ['attribute_art-der-karte' => 'Green'], 'variation_id' => '221']
];
$key = array_search (
'Rot',
array_column(array_column($array, 'attributes'), 'attribute_art-der-karte')
);
echo "variation_id: ". (($key === false) ? 'Not found' : $array[$key]["variation_id"]);
?>
Output:
variation_id: 222
You can access the element variation_id using foreach
// One way using loops identify the non-array element
foreach($array as $ele){
if(!is_array($ele)){
print_r($ele);
}
}
// Otherway for direct calling
print_r($array['variation_id']);

Remove unwanted elements from subarrays in multidimensional array

I have a multidimensional array like this:
[
[
'id' => 1,
'name' => 'John',
'address' => 'Some address 1'
'city' => 'NY'
],
[
'id' => 2,
'name' => 'Jack',
'address' => 'Some address 2'
'city' => 'NY'
]
...
[ ... ]
]
How can I remove elements in all subarrays and only retain the id and name keys with their values?
Would this work?
$result = array_map(function($arr) {
return [
'id' => $arr['id'],
'name' => $arr['name']
];
}, $orig_array);
You want to retain the first two associative elements, so you can make array_slice() calls within array_map(). (Demo)
var_export(
array_map(fn($row) => array_slice($row, 0, 2), $array)
);
Or mapped called of array_intersect_key() against an establish whitelist array. (Demo)
$keep = ['id' => '', 'name' => ''];
var_export(
array_map(
fn($row) => array_intersect_key($row, $keep),
$array
)
)
Or, you could use array destructuring inside of a classic foreach() and make iterated compact() calls. (Demo)
$result = [];
foreach ($array as ['id' => $id, 'name' => $name]) {
$result[] = compact(['id', 'name']);
}
var_export($result);
If you want to edit the same array in place, you can simply iterate over them and unset them.
<?php
$preserve_keys = ['id','name'];
foreach($arr as &$data){
foreach($data as $key => $value){
if(!in_array($key,$preserve_keys)){
unset($data[$key]);
}
}
}
If you want it as a separate result, loop over and add it to the new array.
<?php
$new_result = [];
foreach($arr as $data){
$new_result[] = [
'id' => $data['id'],
'name' => $data['name']
];
}
print_r($new_result);

Convert an array with index and value into an array

I have an array as key => value pair such as:
$array = [ 10 => 'Windows', 12 => 'Keyboard', 15 => 'Monitor' ];
What I would like to achieve without using any foreach or loops the following:
$converted = [
0 => [ 'id' => 10, 'name' => 'Windows'],
1 => [ 'id' => 12, 'name' => 'Keyboard'],
2 => [ 'id' => 15, 'name' => 'Monitor']
];
Here they indices in new array doesn't matter. Any tips??
No foreach and no loop, but now there is a closure:
$result = array_map(function ($id, $name) {
return [
'id' => $id,
'name' => $name
];
}, array_keys($array), array_values($array));
Even if there was a PHP function that did this exactly, it would be using a loop internally.
function do_what_ghazanfar_mir_wants(array $array) {
return array_map(function ($id, $name) {
return [
'id' => $id,
'name' => $name
];
}, array_keys($array), array_values($array));
}
And the single liner is:
$result = do_what_ghazanfar_mir_wants($array);
And the foreach approach for comparison:
$res = [];
foreach ($array as $id => $name) {
$res[] = [ 'id' => $id, 'name' => $name ];
}
If you want to keep it really short then array_walk will do it in one line:
array_walk($array, function(&$value, $key) { $value = ['id' => $key, 'name' => $value]; });
See https://3v4l.org/OEohi
But I think a foreach loop is probably going to be a lot more readable.
Do it with array_map(), Just pass the keys array_keys($array) and values $array as the parameter of your array_map()
<?php
$array = [ 10 => 'Windows', 12 => 'Keyboard', 15 => 'Monitor' ];
function map_by_key($m, $n)
{
return(array('id' => $m, 'name'=>$n));
}
$output = array_map("map_by_key", array_keys($array),$array);
print '<pre>';
print_r($output);
print '</pre>';
?>
DEMO: https://3v4l.org/iTVSm

Find array elements that have a certain key-name prefix

I have an associative array with lots of elements and want to get a list of all elements that have a key name with a certain prefix.
Example:
$arr = array(
'store:key' => 1,
'user' => 'demo',
'store:foo' => 'bar',
'login' => true,
);
// this is where I need help with:
// the function should return only elements with a key that starts with "store:"
$res = list_values_by_key( $arr, 'store:' );
// Desired output:
$res = array(
'store:key' => 1,
'store:foo' => 'bar',
);
You could simply do :
$arr = array(
'store:key' => 1,
'user' => 'demo',
'store:foo' => 'bar',
'login' => true,
);
$arr2 = array();
foreach ($arr as $array => $value) {
if (strpos($array, 'store:') === 0) {
$arr2[$array] = $value;
}
}
var_dump($arr2);
Returns :
array (size=2)
'store:key' => int 1
'store:foo' => string 'bar' (length=3)
This should work for you:
Just grab all keys which starts with store: with preg_grep() from your array. And then do a simple array_intersect_key() call to get the intersect of both arrays.
<?php
$arr = array(
'store:key' => 1,
'user' => 'demo',
'store:foo' => 'bar',
'login' => true,
);
$result = array_intersect_key($arr, array_flip(preg_grep("/^store:/", array_keys($arr))));
print_r($result);
?>
output:
Array
(
[store:key] => 1
[store:foo] => bar
)
From php 5.6 you can use array_filter:
$return = array_filter($array, function ($e) {
return strpos($e, 'store:') === 0;
}, ARRAY_FILTER_USE_KEY);
var_dump($return);
for earlier versions, you can use
$return = array_intersect_key($array, array_flip(array_filter(array_keys($array), function ($e) {
return strpos($e, 'store:') === 0;
})));
Demo.

PHP Question: how to array_intersect_assoc() recursively

Let's say I want to do this:
$a = array_intersect_assoc(
array(
'key1' => array(
'key2' => 'value2'
),
'key3' => 'value3',
'key4' => 'value4'
),
array(
'key1' => array(
'key2' => 'some value not in the first parameter'
),
'key3' => 'another value'
)
);
var_dump( $a );
The printed result is:
array
'key1' =>
array
'key2' => string 'value2' (length=6)
It's clear that values associated with 'key2' in both arrays are not the same, however array_intersect_assoc() still return 'key2' => 'value2' as the intersected value.
Is this the expected behavior of array_intersect_assoc()?
Thanks!
Yes, it's the expected behavior, because the comparison is done using string representations, and the function does not recurse down nested arrays. From the manual:
The two values from the key => value pairs are considered equal only if (string) $elem1 === (string) $elem2 . In other words a strict type check is executed so the string representation must be the same.
If you tried to intersect with an array with 'key1' => 'Array', you'd get the same result because the string representation of an array is always 'Array'.
One of the user-contributed notes, by nleippe, contains a recursive implementation that looks promising (I modified the third line to do string comparison on any non-array values):
function array_intersect_assoc_recursive(&$arr1, &$arr2) {
if (!is_array($arr1) || !is_array($arr2)) {
// return $arr1 == $arr2; // Original line
return (string) $arr1 == (string) $arr2;
}
$commonkeys = array_intersect(array_keys($arr1), array_keys($arr2));
$ret = array();
foreach ($commonkeys as $key) {
$ret[$key] =& array_intersect_assoc_recursive($arr1[$key], $arr2[$key]);
}
return $ret;
}
function array_key_match_recursive(array $main, array $other, $i = 0, &$result = []) {
foreach($main as $key => $value) {
$k = sprintf('%s%s', str_repeat('=', $i), $key);
if (!isset($other[$key])) {
$result[$k][] = 'not key';
}
if (!is_array($value) && empty($other[$key])) {
$result[$k][] = 'value empty';
}
if (is_array($value) && isset($other[$key])) {
array_key_match_recursive($value, $other[$key], ++$i, $result);
}
}
//return (bool) !$result;
return $result;
}
A function that does what you need:
/**
* Get array intersect assoc recursive.
*
* #param mixed $value1
* #param mixed $value2
*
* #return array|bool
*/
function getArrayIntersectAssocRecursive(&$value1, &$value2)
{
if (!is_array($value1) || !is_array($value1)) {
return $value1 === $value2;
}
$intersectKeys = array_intersect(array_keys($value1), array_keys($value2));
$intersectValues = [];
foreach ($intersectKeys as $key) {
if (getArrayIntersectAssocRecursive($value1[$key], $value2[$key])) {
$intersectValues[$key] = $value1[$key];
}
}
return $intersectValues;
}
My version based on #BoltClock version:
function array_intersect_assoc_recursive($arr1, $arr2) {
if (!is_array($arr1) || !is_array($arr2)) {
return $arr1;
}
$commonkeys = array_keys($arr1);
if (!array_key_exists('$', $arr2)){
$commonkeys = array_intersect(array_keys($arr1), array_keys($arr2));
}
$ret = array();
foreach ($commonkeys as $key) {
$ret[$key] = array_intersect_assoc_recursive($arr1[$key], array_key_exists('$', $arr2) ? $arr2['$'] : $arr2[$key]);
}
return $ret;
}
I use this code to filter data inside complex array
example:
$filter = [
'channels' => [
'$' => [
'id' => 1,
'type' => 1,
'count' => 1
]
],
'user' => [
'id' => 1,
'type' => 1
]
];
$data = [
'user' => [
'id' => '1234',
'type' => true,
'counter' => 14,
],
'filteredField' => 4,
'channels' => [
['id' => '567', 'type' => 'other', 'count' => 1345, 'filteredField' => 5,],
['id' => '890', 'type' => 'other', 'count' => 5456, 'filteredField' => 7,],
],
];
print_r(array_intersect_assoc_recursive($data, $filter));
test online:
https://onlinephp.io/c/3be04

Categories