I have two arrays like this :
$data = [
0 => ['id' => 123, 'value' => 'Text'],
1 => ['id' => 124, 'value' => 12]
];
$data2 = [
"custom" => [
0 => ['id' => 123, 'name' => 'Custom1', 'value' => null],
1 => ['id' => 124, 'name' => 'Custom2', 'value' => null]
]
];
I would like to put the value in $data in the value of $data2 instead of "null" values where the ID are matching.
How can I do this ?
I try to do this but does not work :
foreach ($data2['custom'] as $d) {
foreach ($data as $cf) {
if ($cf['id'] == $d['id']):
$cf['value'] = $d['value'];
endif;
}
}
Thanks
Here is a suggestion, first transform the $data array into an array with the id as a key to make the following process simple.
Then process over the $data2 array and in the foreach us the & reference indicator, so that amendments inside the foreach loop are applied to the original $data2 array and not the copy of the $data2 array that would normally be created as part of a foreach loop
$data = [ ['id' => 123, 'value' => 'Text'],['id' => 124, 'value' => 12] ];
$data2 = [ "custom" => [
['id' => 123, 'name' => 'Custom1', 'value' => null],
['id' => 124, 'name' => 'Custom2', 'value' => null]]
];
// transform $data into an array with a useful key
foreach( $data as $d){
$useful[$d['id']] = $d['value'];
}
foreach ( $data2['custom'] as &$data ) {
// first check that the id exists in the new useful array
if ( isset($useful[$data['id']]) ) {
// if it does apply the value to the data2 array
$data['value'] = $useful[$data['id']];
}
}
print_r($data2);
RESULT
Array
(
[custom] => Array
(
[0] => Array
(
[id] => 123
[name] => Custom1
[value] => Text
)
[1] => Array
(
[id] => 124
[name] => Custom2
[value] => 12
)
)
)
In reply to your comment about doing it without using the reference in the loop, yes like this
foreach ( $data2['custom'] as $idx => $data ) {
if ( isset($useful[$data['id']]) ) {
$data2['custom'][$idx]['value'] = $useful[$data['id']];
}
}
Check out this one:
$data = [
0 => ['id' => 123, 'value' => 'Text'],
1 => ['id' => 124, 'value' => 12]
];
$data2 = [
"custom" => [
0 => ['id' => 123, 'name' => 'Custom1', 'value' => null],
1 => ['id' => 124, 'name' => 'Custom2', 'value' => null]
]
];
foreach ($data2['custom'] as $d) {
foreach ($data as $key => $cf) {
if ($cf['id'] == $d['id']):
$data2['custom'][$key]['value'] = $cf['value'];
endif;
}
}
print_r($data2);
You could try to iterate the first array and put the values of it inside the second. If they're always the same size.
Using a foreach go trough the elements on the first array and get the values:
$data = [
0 => ['id' => 123, 'value' => 'Text'],
1 => ['id' => 124, 'value' => 12
]
];
$data2 = [
"custom" => [
0 => ['id' => 123, 'name' => 'Custom1', 'value' => null],
1 => ['id' => 124, 'name' => 'Custom2', 'value' => null]
]
];
foreach ($data as $key=>$singleData){
$data2['custom'][$key]['value'] = $singleData['value'];
}
var_dump($data2);
The ouptup from var_dump() will be:
array(1) {
["custom"]=>
array(2) {
[0]=>
array(3) {
["id"]=>
int(123)
["name"]=>
string(7) "Custom1"
["value"]=>
string(4) "Text"
}
[1]=>
array(3) {
["id"]=>
int(124)
["name"]=>
string(7) "Custom2"
["value"]=>
int(12)
}
}
}
Related
i have a problem with my multidimensional array. I want to remove some items from child array by $id value.
here is my multidimensional example array and selectedIds:
$myArray = [
['id' => '2',
'name' => 'Punk'
],[
'id' => '5',
'name' => 'Rock',
'children' => [
'30' => ['id' => '30',
'name' => 'Hard Rock',
'parentId' => '5'
],
'40' => ['id' => '40',
'name' => 'Soft Rock',
'parentId' => '5'
],
'50' => ['id' => '50',
'name' => 'Glam Rock',
'parentId' => '5'
]
]
]
];
$selectedIds = [2,5,30];
and i want to remove from array those items which are not in selectedIds array.
so i want to have output:
$outputArray = [
[
'id' => '2',
'name' => 'Punk'
],[
'id' => '5',
'name' => 'Rock',
'children' => [
'30' => ['id' => '30',
'name' => 'Hard Rock',
'parentId' => '5']
]
]
];
i try to make it with foreach and array_key_exist but its not correct:
foreach ($myArray as $key=>$value) {
if (array_key_exists('children', $value)) {
foreach ($selectedIds as $id) {
if (isset($value['children'][$id])) {
$outputArray[] = $value['children'][$id];
}
}
}
}
print_r($outputArray);
this outpus is only item with id 30
write else part into your code if array has no children key
else{
foreach ($selectedIds as $id) {
if ($value['id'] == $id) {
$outputArray[$key] = $value;
}
}
}
Final code
<?PHP
$myArray = [
[
'id' => '2',
'name' => 'Punk'
],
[
'id' => '5',
'name' => 'Rock',
'children' => [
'30' => ['id' => '30',
'name' => 'Hard Rock',
'parentId' => '5'
],
'40' => ['id' => '40',
'name' => 'Soft Rock',
'parentId' => '5'
],
'50' => ['id' => '50',
'name' => 'Glam Rock',
'parentId' => '5'
]
]
]
];
$selectedIds = [2,5,30];
foreach ($myArray as $key=>$value) {
if (array_key_exists('children', $value)) {
foreach ($selectedIds as $id) {
if (isset($value['children'][$id])) {
$outputArray[$key]['id'] = $value['id'];
$outputArray[$key]['name'] = $value['name'];
$outputArray[$key]['children'][$id] = $value['children'][$id];
}
}
}else{
foreach ($selectedIds as $id) {
if ($value['id'] == $id) {
$outputArray[$key] = $value;
}
}
}
}
echo "<pre>";
print_r($outputArray);
?>
Output
Array
(
[0] => Array
(
[id] => 2
[name] => Punk
)
[1] => Array
(
[id] => 5
[name] => Rock
[children] => Array
(
[30] => Array
(
[id] => 30
[name] => Hard Rock
[parentId] => 5
)
)
)
)
Hey i make other code more simple. That´s here:
just change a bit the foreach content:
foreach ($myArray as $key=>&$value) {
if (array_key_exists('children', $value)) {
$value['children'] = array_intersect_key($value['children'], array_flip($selectedIds));
}
}
Use array_flipfor transform keys on values and array_intersect_keyfor get only they id´s that exist in 2 arrays.
here you can see a live demo
NOTE: take care that i´m passing the value by referer &$value in the foreach for modify the original array, if you dont want this just duplicate the original array and modify the second.
I have this two-dimensional array
array
(
0 => array
(
"id_category" => 3
, "name" => "mesa plegable"
),
1 => array
(
"id_category" => 4
, "name" => "cama plegable"
),
2 => array
(
"id_category" => 5
, "name" => "sillas plegables"
),
3 => array
(
"id_category" => 6
, "name" => "bicicleta plegable"
),
4 => array
(
"id_category" => 7
, "name" => "carpas plegables"
),
5 => array
(
"id_category" => 8
, "name" => "bicicleta estatica plegable"
),
6 => array
(
"id_category" => 9
, "name" => "bicicleta electrica plegable"
),
7 => array
(
"id_category" => 10
, "name" => "cinta de correr plegable"
),
8 => array
(
"id_category" => 11
, "name" => "carro compra plegable"
),
9 => array
(
"id_category" => 12
, "name" => "mesa plegable cocina"
),
10 => array
(
"id_category" => 13
, "name" => "puertas plegables"
),
11 => array
(
"id_category" => 14
, "name" => "tumbona plegable"
),
12 => array
(
"id_category" => 15
, "name" => "escalera plegable"
),
13 => array
(
"id_category" => 16
, "name" => "mesa plegable pared"
),
);
And I would like this result:
array (
'mesa' =>
array (
0 => 'mesa plegable',
1 => 'mesa plegable cocina',
2 => 'mesa plegable pared',
),
'cama' =>
array (
0 => 'cama plegable',
),
'sillas' =>
array (
0 => 'sillas plegables',
),
'bicicleta' =>
array (
0 => 'bicicleta plegable',
1 => 'bicicleta estatica plegable',
2 => 'bicicleta electrica plegable',
),
'carpas' =>
array (
0 => 'carpas plegables',
),
'cinta' =>
array (
0 => 'cinta de correr plegable',
),
'carro' =>
array (
0 => 'carro compra plegable',
),
'puertas' =>
array (
0 => 'puertas plegables',
),
'tumbona' =>
array (
0 => 'tumbona plegable',
),
'escalera' =>
array (
0 => 'escalera plegable',
),
)
I am a beginner, so there may be things that are not done this way. Please understand ;)
$write_element = '';
foreach ($original_array as $element){
$name= explode(" ",$element['name']);
$clean_name = $nombre_cat[0];
$group_by_name = array_map("myfunction",$original_array,$clean_name);
}
function myfunction($original_array,$clean_name)
{
//this is what I don't know how to do
if $clean_name exists in $original_array push in new array to return all matches
}
I know how to run two foreach one inside the other and look for matches, but I think an array map would be faster and cleaner, right? Maybe I'm wrong about this too.
Can you help me please
$data - represents the raw data.
$result - represents the final expected output/result.
$result = [];
array_map(function ($value) use (&$result) {
if (!array_key_exists($key = substr($value["name"], 0, strpos($value["name"], " ")), $result)) $result[$key] = [];
$result[$key][] = $value["name"];
}, $data);
var_export($result);
Addendum:
Alternatively, you could use array_reduce() as suggested by #ryan-vincent in a comment:
Rather than use array_map, I would have used array_reduce. Why?
array_map is designed to give give you back an array that has the
same number of entries as the input where each entry is modified by
the callback. The array_reduce function is designed to return a
result that is definitely different from the input array. It can be
a value or an array, which is why I would use it for your requirement.
$result = array_reduce($data, function ($result, $value) {
if (!array_key_exists($key = substr($value["name"], 0, strpos($value["name"], " ")), $result)) $result[$key] = [];
$result[$key][] = $value["name"];
return $result;
}, []);
var_export($result);
here is my attempt
input array is $array
output array is $output
you can copy and paste this code at this online php code testing site
<?php
// assign input data
$array = [
[
'id_category' => 3,
'name' => 'mesa plegable'
],
[ 'id_category' => 4,
'name' => 'cama plegable'
],
[
'id_category' => 5,
'name' => 'sillas plegables'
],
[
'id_category' => 6,
'name' => 'bicicleta plegable'
],
[
'id_category' => 7,
'name' => 'carpas plegables'
],
[
'id_category' => 8,
'name' => 'bicicleta estatica plegable'
],
[
'id_category' => 9,
'name' => 'bicicleta electrica plegable'
],
[
'id_category' => 10,
'name' => 'cinta de correr plegable'
],
[
'id_category' => 11,
'name' => 'carro compra plegable'
],
[
'id_category' => 12,
'name' => 'mesa plegable cocina'
],
[
'id_category' => 13,
'name' => 'puertas plegables'
],
[
'id_category' => 14,
'name' => 'tumbona plegable'
],
[
'id_category' => 15,
'name' => 'escalera plegable'
],
[
'id_category' => 16,
'name' => 'mesa plegable pared'
]
];
// get strings
$strings = [];
foreach( $array as $key => $value ){
$strings[] = $value['name'];
}
// create group headings
$string_group_names = [];
foreach( $strings as $key => $value ){
$string_group_names[] = explode(" ", $value)[0];
}
// clean array to remove duplicates
$string_group_names = array_unique($string_group_names);
// create output array
$output = [];
foreach( $string_group_names as $key => $value ){
$items = [];
foreach( $strings as $key2 => $value2 ){
$isMatch = explode(' ', $value2)[0] == $value;
if($isMatch){
$items[] = $value2;
}
}
$output[$value] = $items;
}
// do something with the output
var_dump($output);
Input Data
$array = [
[
'id_category' => 3,
'name' => 'mesa plegable'
],
[ 'id_category' => 4,
'name' => 'cama plegable'
],
[
'id_category' => 5,
'name' => 'sillas plegables'
],
[
'id_category' => 6,
'name' => 'bicicleta plegable'
],
[
'id_category' => 7,
'name' => 'carpas plegables'
],
[
'id_category' => 8,
'name' => 'bicicleta estatica plegable'
],
[
'id_category' => 9,
'name' => 'bicicleta electrica plegable'
],
[
'id_category' => 10,
'name' => 'cinta de correr plegable'
],
[
'id_category' => 11,
'name' => 'carro compra plegable'
],
[
'id_category' => 12,
'name' => 'mesa plegable cocina'
],
[
'id_category' => 13,
'name' => 'puertas plegables'
],
[
'id_category' => 14,
'name' => 'tumbona plegable'
],
[
'id_category' => 15,
'name' => 'escalera plegable'
],
[
'id_category' => 16,
'name' => 'mesa plegable pared'
]
];
Output
array(10) {
["mesa"]=>
array(3) {
[0]=>
string(13) "mesa plegable"
[1]=>
string(20) "mesa plegable cocina"
[2]=>
string(19) "mesa plegable pared"
}
["cama"]=>
array(1) {
[0]=>
string(13) "cama plegable"
}
["sillas"]=>
array(1) {
[0]=>
string(16) "sillas plegables"
}
["bicicleta"]=>
array(3) {
[0]=>
string(18) "bicicleta plegable"
[1]=>
string(27) "bicicleta estatica plegable"
[2]=>
string(28) "bicicleta electrica plegable"
}
["carpas"]=>
array(1) {
[0]=>
string(16) "carpas plegables"
}
["cinta"]=>
array(1) {
[0]=>
string(24) "cinta de correr plegable"
}
["carro"]=>
array(1) {
[0]=>
string(21) "carro compra plegable"
}
["puertas"]=>
array(1) {
[0]=>
string(17) "puertas plegables"
}
["tumbona"]=>
array(1) {
[0]=>
string(16) "tumbona plegable"
}
["escalera"]=>
array(1) {
[0]=>
string(17) "escalera plegable"
}
}
Is there a way to mutate an array using array_reduce in PHP?
I'm trying to do something like this:
Given some ordered list of ids:
$array = [["id" => 1], ["id" => 13], ["id" => 4]];
And a tree that has a subtree matching the corresponding ids:
$tree = [
"id" => 2334,
"children" => [
[
"id" => 111,
"children" => []
],
[
"id" => 1, // <- this is a match
"children" => [
[
"id" => 13, // <- this is a match
"children" => [
[
"id" => 4, // <- this is a match
"children" => []
],
[
"id" => 225893,
"children" => []
],
[
"id" => 225902,
"children" => []
]
]
]
]
]
]
];
How can I mutate the arrays in that subtree?
I'm currently trying to use array_reduce to walk down the tree and mutate it. However, the mutation isn't being applied to the originally passed in $tree.
array_reduce($array, function (&$acc, $item) {
$index = array_search($item['id'], array_column($acc['children'], 'id'));
$acc['children'][$index]['mutated'] = true; // mutation here
return $acc['children'][$index];
}, $tree);
echo "<pre>";
var_dump($tree); // $tree is unchanged here
echo "</pre>";
Why is $tree not mutated after the running above array_reduce?
Is there a way to use foreach in this case?
I think this function will do what you want. It recurses down $tree, looking for id values that are in $array and setting the mutation flag for those children:
function mutate(&$tree, $array) {
if (in_array($tree['id'], array_column($array, 'id'))) {
$tree['mutated'] = true;
}
foreach ($tree['children'] as &$child) {
mutate($child, $array);
}
}
mutate($tree, $array);
var_export($tree);
Output:
array (
'id' => 2334,
'children' => array (
0 => array (
'id' => 111,
'children' => array ( ),
),
1 => array (
'id' => 1,
'children' => array (
0 => array (
'id' => 13,
'children' => array (
0 => array (
'id' => 4,
'children' => array ( ),
'mutated' => true,
),
1 => array (
'id' => 225893,
'children' => array ( ),
),
2 => array (
'id' => 225902,
'children' => array ( ),
),
),
'mutated' => true,
),
),
'mutated' => true,
),
),
)
Demo on 3v4l.org
Edit:
Trying to avoid doing a loop outside of the $data array you see. As I need to do this a couple of times and it looks messy.
I have got an array similar to this:
$links = [
[
'type_id' => '1',
'url' => ''
],
[
'type_id' => '2',
'url' => ''
]
];
$types = [
[
'id' => 1,
'value' => 'facebook'
],
[
'id' => 2
'value' => 'twitter'
]
];
$data = [
'primary' => [
'address_details' => [],
'contact_details' => [],
'social_links' => $links
]
];
I need the keys within my $data['primary']['social_links'] to use the $type['value'] rather than just being 0, 1, etc...
So $data would look like:
$data = [
'primary' => [
'address_details' => [],
'contact_details' => [],
'social_links' => [
'facebook' => [
'type_id' => '1',
'url' => ''
],
'twitter' => [
'type_id' => '2',
'url' => ''
]
]
]
];
Is there a way I can do this with array_map or something?
You can just use array_combine with the output of the value column of $types (generated using array_column) as keys and the values from $links:
$data = [
'primary' => [
'address_details' => [],
'contact_details' => [],
'social_links' => array_combine(array_column($types, 'value'), $links)
]
];
print_r($data);
Output:
Array (
[primary] => Array (
[address_details] => Array ( )
[contact_details] => Array ( )
[social_links] => Array (
[facebook] => Array (
[type_id] => 1
[url] =>
)
[twitter] => Array (
[type_id] => 2
[url] =>
)
)
)
)
Demo on 3v4l.org
Update
Based on the edit to OPs question, things get a lot more complicated to give a one-line solution. This should work:
$data = [
'primary' => [
'address_details' => [],
'contact_details' => [],
'social_links' => array_map(function ($v) use ($links) { return $links[array_search($v, array_column($links, 'type_id'))]; }, array_column($types, 'id', 'value'))
]
];
Demo on 3v4l.org
A simple for loop can do it:
https://3v4l.org/h47MG
<?php
$links = [
[
'type_id' => '1',
'url' => ''
],
[
'type_id' => '2',
'url' => ''
]
];
$types = [
[
'value' => 'facebook'
],
[
'value' => 'twitter'
]
];
$result = [];
for($i = 0, $len = count($types); $i < $len; $i++) {
$result[$types[$i]['value']] = $links[$i];
}
$data = [
'primary' => [
'address_details' => [],
'contact_details' => [],
'social_links' => $result
]
];
var_dump($data);
You could use a loop to modify the array directly :
for($i=0; $i < sizeof($links); $i++) {
$links[$types[$i]['value']] = $links[$i];
unset($links[$i]);
}
var_dump($links);
Output :
["facebook"]=> array(2) {
["type_id"]=> string(1) "1"
["url"]=> string(0) ""
}
["twitter"]=> array(2) {
["type_id"]=> string(1) "2"
["url"]=> string(0) ""
}
Or by using array_combine if you do not want a loop, per your comment on another answer :
array_combine(array_column($types, 'value'), $links)
<pre><code>
$social_links = [];
foreach ($types as $type):
$social_links[$type['value']] = $links[$key];
endforeach;
$data = [
'primary' => [
'address_details' => [],
'contact_details' => [],
'social_links' => $social_links
]
];
print_r($data);
</code></pre>
I am trying to compare two associative arrays and get the difference based upon the value and also based upon the key. I have tried using an array_filter with a closure
The two arrays are like so:
Array 1
$newArr = [
0 => [
'id' => 'UT5',
'qty' => '4'
],
1 => [
'id' => 'WRO',
'qty' => '3'
],
2 => [
'id' => 'SHO',
'qty' => '3'
]
];
Array 2
$oldArr = [
0 => [
'id' => 'SHO',
'qty' => '1'
],
1 => [
'id' => 'UT5',
'qty' => '2'
],
];
My desired output is as follows:
array(3)
{
["UT5"]=> int(2)
["SHO"]=> int(2)
["WRO"]=> int(3)
}
I have gotten this far:
<?php
$newArr = [
0 => [
'id' => 'UT5',
'qty' => '4'
],
1 => [
'id' => 'WRO',
'qty' => '3'
],
2 => [
'id' => 'SHO',
'qty' => '3'
]
];
$oldArr = [
0 => [
'id' => 'SHO',
'qty' => '1'
],
1 => [
'id' => 'UT5',
'qty' => '2'
],
];
$toAdd = [];
foreach ($newArr as $item) {
$itemsToAdd = array_walk($oldArr, function ($k) use ($item, &$toAdd) {
if ($k['id'] == $item['id']) {
$toAdd[$k['id']] = max($k['qty'], $item['qty']) - min($k['qty'], $item['qty']);
}
});
}
var_dump($toAdd); die();
However with this function, my current output is:
array(2) {
["UT5"]=> int(2)
["SHO"]=> int(2)
}
Note that WRO is missing. Is there a way that I can add a conditional to accurately check for this? I have tried a few solution such as !in_array and else but neither are giving me the desired output.
Any help is appreciated! Thanks!
That's an easy one, your code saves a value ONLY if the key is present in both arrays. Just add a clause to check if the key DOESN'T exist in the old array. (also do the opposite in case the old array has a key the new one doesn't have)
if (!isset(old array [ new array key ]){
$newArray[new array key] = new array key and values;
Your program structure is optimized for the computer and is too complex to follow as a human, I rewrote it entirely.
<?php
$newArr = [0 => ['id' => 'UT5', 'qty' => '4'], 1 => ['id' => 'WRO', 'qty' => '3'], 2 => ['id' => 'SHO', 'qty' => '3']];
$oldArr = [0 => ['id' => 'SHO', 'qty' => '1'], 1 => ['id' => 'UT5', 'qty' => '2'], ];
$newReset = [];
foreach( $newArr as $item ) {
$newReset[$item['id']] = $item['qty'];
}
$oldReset = [];
foreach( $oldArr as $item ) {
$oldReset[$item['id']] = $item['qty'];
}
foreach( $newReset as $key => $val ) {
if( isset( $oldReset[$key] ) ) {
$toAdd[$key] = max( $oldReset[$key], $val ) - min( $oldReset[$key], $val );
}
else $toAdd[$key] = intval($val);
}
var_dump( $toAdd );
And here's the result.
array(3) {
["UT5"]=>
int(2)
["WRO"]=>
int(3)
["SHO"]=>
int(2)
}
Make it in one pass
$toAdd = [];
foreach ($newArr as $item)
$toAdd[$item['id']] = $item['qty'];
foreach ($oldArr as $item)
if (isset($toAdd[$item['id']]))
$toAdd[$item['id']] = abs($toAdd[$item['id']] - $item['qty']);
else
$toAdd[$item['id']] = abs($item['qty']);
print_r($toAdd);