Hello i have array like this with variable depth:
$array = [ // depth of array and number of values are variable
'this' => [
'a' => [
'b' => 'some value'
],
'c' => [
'd' => 'some value'
],
],
'that' => [
'path' => [
'to' => [
'val' => 'some value'
],
]
]
];
and i need to have this:
$array['this.a.b'] => 'some value';
$array['this.c.d'] => 'some value';
$array['that.path.to.val'] => 'some value';
or this can be better:
$array[
0 => [
'key' => 'this.a.b',
'val' => 'some value'
],
1 => [
'key' => 'this.c.d',
'val' => 'some value'
],
2 => [
'key' => 'that.path.to.val',
'val' => 'some value'
],
]
I need to take data from array and put them to easy form like:
<input name="this.a.b" value="some value">
I tried something like this, but it doesn't work well.
private static function reformat($input, $k = '', &$keys = [])
{
foreach($input as $key => $val) {
$k .= '.' . $key;
if (is_array($val)){
static::reformat($val, $k, $keys);
}else{
$keys[$k] = $val;
}
}
return $keys;
}
Thanks for help
Try this
$array['this']['a']['b'];
$array['this']['c']['d'];
$array['this']['path']['to']['val'];
or
function getVal($array, $key, $d='.') {
$keyArray = explode($d, $key);
$value = $array;
foreach($keyArray as $k){
if(isset($value[$k]))
$value = $value[$k];
else {
$value = "";
break;
}
}
return $value;
}
echo getVal($array, 'this.path.to.val');
You can make your user define function as
$array = [
'this' => [
'a' => [
'b' => 'some value'
],
'c' => [
'd' => 'some value'
],
],
'that' => [
'path' => [
'to' => [
'val' => 'some value'
],
]
]
];
function makesingledimesional($arr,$par = ''){
$result = [];
$final = [];
foreach($arr as $key => $value){
if(is_array($value) && count($value)>0){
$par .= "$key.";
$result[$par] = makesingledimesional($value,$par);
}else{
$result[$par.$key] = $value;
}
}
array_walk_recursive($result,function($v,$k)use(&$final){$final[$k] = $v;});
return $final;
}
print_r(makesingledimesional($array));
Output:
Array
(
[this.a.b] => some value
[this.a.c.d] => some value
[this.that.path.to.val] => some value
)
Demo
I found wanted solution and here it is:
function shorten($inputArray, $path = null, $separator = ".")
{
$data = array();
if (!is_null($path)) {
$path = $path . $separator;
}
if (is_array($inputArray)) {
foreach ($inputArray as $key => &$value) {
if (!is_array($value)) {
$data[$path . $key] = $value;
} else {
$data = array_merge($data, shorten($value, $path . $key, $separator));
}
}
}
return $data;
}
Output
Array
(
[this.a.b] => some value
[this.c.d] => some value
[that.path.to.val] => some value
)
Demo
Related
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
I have 2 sets of array:
Data:
$data = [
[
'company_code' => 'ABC',
'supplier_codes' => [
'S-2',
'S-3',
'S-5',
],
],
];
Source (from database):
$database = [
'company_code' => 'ABC',
'suppliers' => [
[
'code' => 'S-1',
],
[
'code' => 'S-2',
'reference' => '12345'
],
[
'code' => 'S-3',
],
[
'code' => 'S-4',
'reference' => 'some string',
]
],
];
What I need to achieve:
If a supplier code is missing in $data but exists in $database,
remove it from $database.
If a supplier code exists in $data but missing in $database, add it into $database
The output of the example here should be as follows:
$output = [
'company_code' => 'ABC',
'suppliers' => [
[
'code' => 'S-2',
'reference' => '12345'
],
[
'code' => 'S-3',
],
[
'code' => 'S-5',
]
],
];
I was thinking of removing the suppliers subarray, then reconstruct the structure based on the data from supplier_codes. But the problem is some of the entries in suppliers may have an optional field called reference.
Try this
<?php
$data = [
[
'company_code' => 'ABC',
'supplier_codes' => ['S-2','S-3','S-5'],
],
];
$database = [
'company_code' => 'ABC',
'suppliers' => [
[
'code' => 'S-1',
],
[
'code' => 'S-2',
'reference' => '12345'
],
[
'code' => 'S-3',
],
[
'code' => 'S-4',
'reference' => 'some string',
]
],
];
foreach($database['suppliers'] as $k=>$v){
foreach($data as $kd=>$vd){
$valueremove = false;
$removeIndex = '';
foreach($vd['supplier_codes'] as $key=>$val){
if($val == $v['code']){
$valueremove = false;
$removeIndex = '';
break;
} else {
$valueremove = true;
$removeIndex = $k;
}
}
if($valueremove == true){
unset($database['suppliers'][$removeIndex]);
} else {
$valueinsert = false;
foreach($data as $kd=>$vd){
foreach($vd['supplier_codes'] as $key=>$val){
foreach($database['suppliers'] as $kc=>$vc){
if($val == $vc['code']){
$valueinsert = false;
$insertIndex = '';
$insertVal = '';
break;
} else {
$valueinsert = true;
$insertIndex = count($database['suppliers'])+1;
$insertVal = $val;
}
}
if($valueinsert == true){
$database['suppliers'][$insertIndex] = array('code'=>$insertVal);
}
}
}
}
}
}
echo "<PRE>"; print_r($database);
I end up solving my problem this way:
$result = $database;
$result['suppliers'] = [];
foreach($data as $tag) {
foreach($tag['supplier_codes'] as $code) {
$found = false;
foreach($database['suppliers'] as $supplier) {
if($supplier['code'] === $code) {
$result['suppliers'][] = $supplier;
$found = true;
}
}
if(!$found) {
$result['suppliers'][] = ['code' => $code];
}
}
}
Output of print_r($result);:
Array
(
[company_code] => ABC
[suppliers] => Array
(
[0] => Array
(
[code] => S-2
[reference] => 12345
)
[1] => Array
(
[code] => S-3
)
[2] => Array
(
[code] => S-5
)
)
)
I have array with this format:
$components = [
[
'name' => 'ADIPIC ACID',
'cas' => '123',
'einecs' => '321'
],
[
'name' => 'ADIPIC ACID/DIMETHY- LAMINOHYDROXY- PROPYL DIETHYLENE- TRIAMINE COPOLYMER',
'cas' => '456',
'einecs' => '654'
]
]
I need to find each name which has a / character, break it and create a new entry in the $components array with cas and einecs being empty string.
Also the first part of the name will have cas and einecs values from the original entry.
Expected array:
$components = [
[
'name' => 'ADIPIC ACID',
'cas' => '123',
'einecs' => '321'
],
[
'name' => 'ADIPIC ACID',
'cas' => '456',
'einecs' => '654'
],[
'name' => 'DIMETHY- LAMINOHYDROXY- PROPYL DIETHYLENE- TRIAMINE COPOLYMER',
'cas' => '',
'einecs' => ''
]
]
How can I do this?
Quite crude I admit and it doesn't account for multiple / characters in a value but it does return the result expected.
foreach( $components as $index=> $arr ){
foreach( $arr as $key => $value ){
if( $key=='name' && strstr( $value, '/' ) ){
list($pre,$post)=explode('/',$value);
$components[$index][$key]=$pre;
$components[]=array('name'=>$post,'cas'=>'','einecs'=>'');
}
}
}
<?php
$components = [
[
'name' => 'ADIPIC ACID',
'cas' => '123',
'einecs' => '321'
],
[
'name' => 'ADIPIC ACID/DIMETHY- LAMINOHYDROXY- PROPYL DIETHYLENE- TRIAMINE COPOLYMER',
'cas' => '456',
'einecs' => '654'
]
];
$new = [];
foreach ($components as &$component) {
if ($items = explode('/', $component['name'])) {
$component['name'] = array_shift($items);
$new = array_merge($new, $items);
}
}
foreach ($new as $item) {
$components[] = ['name' => $item, 'cas' => '', 'einecs' => ''];
}
var_dump($components);
I would try something like this where I use the explode function using the '/' character on the name of each component. Then I'd create a new array of all the new components taking the values of the component being evaluated.
$newComponents = array();
foreach($components as $component) {
foreach(explode('/', $component['name']) as $newComponentName) {
$newComponents[] = array('name' =>$newComponentName,
'cas' => $component['cas'],
'einecs' => $component['einecs']);
}
}
foreach($components as $component)
{
if(strpos($component["name"],"/") !== false){
$temp = explode("/",$component["name"]);
$components[] = new array("name"=>$temp[1], "cas"=>"", "einecs"=>"");
}
}
The question is simple, I want to create the array below dynamically, but the code I got now only outputs the last row. Is there anybody who knows what is wrong with my dynamically array creation?
$workingArray = [];
$workingArray =
[
0 =>
[
'id' => 1,
'name' => 'Name1',
],
1 =>
[
'id' => 2,
'name' => 'Name2',
]
];
echo json_encode($workingArray);
/* My not working array */
$i = 0;
$code = $_POST['code'];
$dynamicArray = [];
foreach ($Optionsclass->get_options() as $key => $value)
{
if ($value['id'] == $code)
{
$dynamicArray =
[
$i =>
[
'id' => $key,
'name' => $value['options']
]
];
$i++;
}
}
echo json_encode($dynamicArray);
You dont need to have the $i stuff that is adding another level to your array that you dont want.
$code = $_POST['code'];
$dynamicArray = [];
foreach ($Optionsclass->get_options() as $key => $value)
{
if ($value['id'] == $code)
{
$dynamicArray[] = ['id' => $key, 'name' => $value['options'];
}
}
echo json_encode($dynamicArray);
You are creating a new dynamic array at each iteration:
$dynamicArray =
[
$i =>
[
'id' => $key,
'name' => $value['options']
]
];
Instead, declare $dynamicArray = []; above the foreach, and then use:
array_push($dynamicArray, [ 'id' => $key, 'name' => $value['options']);
inside the array.
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