PHP Map to use key in value for associative array - php

I have the following given associative array, showing me how many items I have of each key.
'story' => 10
'image' => 20
'video' => 30
'audio' => 40
I'm trying to transform the array so I can use the key string inside my value, I want to get the following result
'story' => 'Story (10)'
'image' => 'Image (20)'
'video' => 'Video (30)'
'audio' => 'Audio (40)'
I've tried
I've tried the following method, but it resets the keys to indexes (0, 1, 2, 3)
return array_map(function ($key, $value) {
return $key . "(" . $value . ")";
}, array_keys($mergedArray), $mergedArray);

Try using array_walk() instead of array_map()
array_walk($mergedArray, function (&$value, $key) { $value = ucwords($key) . "($value)"; });
print_r($mergedArray);
Working demo
Output:
Array
(
[story] => Story(10)
[image] => Image(20)
[video] => Video(30)
[audio] => Audio(40)
)

$arr = [
"story" => 10,
"image" => 20,
"video" => 30,
"audio" => 40
];
foreach($arr as $key => $value) {
$arr[$key] = ucfirst($key)." (".$value.")";
}
Here is the demo

Related

Loop an array and retain only elements that relate to a specific key with a qualifying value

I have this array :
(
[id] => block_5df755210d30a
[name] => acf/floorplans
[data] => Array
(
[floorplans_0_valid_for_export] => 0
[floorplans_0_title] => title 1
[floorplans_0_house_area] => 40m²
[floorplans_0_bedrooms] => 1
[floorplans_1_valid_for_export] => 1
[floorplans_1_title] => title xx
[floorplans_1_house_area] => 90m²
[floorplans_1_bedrooms] => 2
[floorplans_2_valid_for_export] => 1
[floorplans_2_title] => title 2
[floorplans_2_house_area] => 50m²
[floorplans_2_bedrooms] => 1
[floorplans] => 3
)
)
As we can see in the data, we have fields (floorplans_X_valid_for_export).
What I want to do is to get the data only when this field equal to 1.
So from the given example, I want to keep only these fields:
[floorplans_1_valid_for_export] => 1
[floorplans_1_title] => title xx
[floorplans_1_house_area] => 90m²
[floorplans_1_bedrooms] => 2
[floorplans_2_valid_for_export] => 1
[floorplans_2_title] => title 2
[floorplans_2_house_area] => 50m²
[floorplans_2_bedrooms] => 1
This is an odd schema, but it can be done by iterating through the array and searching for keys where "valid_for_export" equals 1, and then using another array of field "stubs" to get the associated items by a unique identifier of X in floorplans_X_valid_for_export
$array = [
'floorplans_0_valid_for_export' => 0,
'floorplans_0_title' => 'title 1',
'floorplans_0_house_area' => '40m²',
'floorplans_0_bedrooms' => 1,
'floorplans_1_valid_for_export' => 1,
'floorplans_1_title' => 'title xx',
'floorplans_1_house_area' => '90m²',
'floorplans_1_bedrooms' => '2',
'floorplans_2_valid_for_export' => 1,
'floorplans_2_title' => 'title 2',
'floorplans_2_house_area' => '50m²',
'floorplans_2_bedrooms' => 1,
'floorplans' => 3
];
$stubs = [
'floorplans_%s_valid_for_export',
'floorplans_%s_title',
'floorplans_%s_house_area',
'floorplans_%s_bedrooms'
];
$newArr = [];
foreach ($array as $key => $value) {
if (strpos($key, 'valid_for_export') && $array[$key] == 1) {
$intVal = filter_var($key, FILTER_SANITIZE_NUMBER_INT);
foreach ($stubs as $stub) {
$search = sprintf($stub, $intVal);
if (isset($array[$search])) {
$newArr[$search] = $array[$search];
} else {
// key can't be found, generate one with null
$newArr[$search] = null;
}
}
}
}
echo '<pre>';
print_r($newArr);
Working: http://sandbox.onlinephpfunctions.com/code/23a225e3cefa2dc9cc97f53f1cbae0ea291672c0
Use a parent loop to check that the number-specific valid_for_export value is non-empty -- since it is either 0 or non-zero.
If so, then just push all of the associated elements into the result array.
Some reasons that this answer is superior to the #Alex's answer are:
Alex's parent loop makes 13 iterations (and the same number of strpos() calls); mine makes just 3 (and only 3 calls of empty()).
$array[$key] is more simply written as $value.
Sanitizing the $key to extract the index/counter is more overhead than necessary as demonstrated in my answer.
Code (Demo)
$array = [
'floorplans_0_valid_for_export' => 0,
'floorplans_0_title' => 'title 1',
'floorplans_0_house_area' => '40m²',
'floorplans_0_bedrooms' => 1,
'floorplans_1_valid_for_export' => 1,
'floorplans_1_title' => 'title xx',
'floorplans_1_house_area' => '90m²',
'floorplans_1_bedrooms' => '2',
'floorplans_2_valid_for_export' => 1,
'floorplans_2_title' => 'title 2',
'floorplans_2_house_area' => '50m²',
'floorplans_2_bedrooms' => 1,
'floorplans' => 3
];
$labels = ['valid_for_export', 'title', 'house_area', 'bedrooms'];
$result = [];
for ($i = 0; $i < $array['floorplans']; ++$i) {
if (!empty($array['floorplans_' . $i . '_valid_for_export'])) {
foreach ($labels as $label) {
$key = sprintf('floorplans_%s_%s', $i, $label);
$result[$key] = $array[$key];
}
}
}
var_export($result);
Output:
array (
'floorplans_1_valid_for_export' => 1,
'floorplans_1_title' => 'title xx',
'floorplans_1_house_area' => '90m²',
'floorplans_1_bedrooms' => '2',
'floorplans_2_valid_for_export' => 1,
'floorplans_2_title' => 'title 2',
'floorplans_2_house_area' => '50m²',
'floorplans_2_bedrooms' => 1,
)
With that constructed data it might be hard (not impossble tho), hovewer i would suggest to change it to multidimensional arrays so you have something like:
[floorplans][0][valid_for_export] => 0
[floorplans][0][title] => title 1
[floorplans][0][house_area] => 40m²
[floorplans][0][bedrooms] => 1
[floorplans][1][valid_for_export] => 1
[floorplans][1][title] => title xx
[floorplans][1][house_area] => 90m²
Rought sollution
It is not the best approach, but it should work if you dont need anything fancy, and know that structure of data wont change in future
$keys = [];
$for($i=0;$i<$array['floorplans'];++$i) {
if(isset($array['floorplans_'.$i.'_valid_for_export']) && $array['floorplans_'.$i.'_valid_for_export']===1) {
$keys[] = $i;
}
}
print_r($keys);

Array manipulation (compare) by specific algortihm

I have 2 array and i need compare these arrays by my specific algorithm.
Firstly, my arrays:
$old = [
'pencil' => 'red',
'eraser' => 'green',
'bag' => 'blue'
];
$new = [
'pencil' => '',
'eraser' => '',
'computer' => 'mac',
'bag' => '',
'activity' => [
'jumping',
'pool',
'reading'
]
];
Then, I wanna get this output:
$output = [
'pencil' => 'red', // old value
'eraser' => 'green', // old value
'bag' => 'blue', // old value
'computer' => 'mac', // new key & values
'activity' => [ // new key & values
'jumping',
'pool',
'reading'
]
];
So, elements (array item) in both old and new arrays will be added to the output but values should come from the old array.
The elements (array item) in the new array should be transferred to output exactly.
I wanna support my question with a photo attachment ( the sequence on the photo may not match the sequence on the my arrays ($old, $new) ):
photo
Use array_merge in order to merge element of two array:
$result = array_merge($new, $old);
The values from the second array ($old) will be merged on the first array so if you have a key in both array, the second one will be presented in the result.
I think the following code can achieve what you are looking for:
$output = []
foreach($old as $key => $value){
$output[$key] = $value;
}
foreach($new as $key => $value){
if(!array_key_exists($key, $output)){
$output[$key] = $value;
}
}
Here is my solution,
$old = [
'pencil' => 'red',
'eraser' => 'green',
'bag' => 'blue'
];
$new = [
'pencil' => '',
'eraser' => '',
'computer' => 'mac',
'bag' => '',
'activity' => [
'jumping',
'pool',
'reading'
]
];
$output = [];
foreach ($new as $newkey => $newvalue) {
if($newvalue!=""){
$output = [$old+$new];
}
}
echo "<pre>";
print_r($output);
echo "</pre>";
exit;
Here output look like,
Array
(
[0] => Array
(
[pencil] => red
[eraser] => green
[bag] => blue
[computer] => mac
[activity] => Array
(
[0] => jumping
[1] => pool
[2] => reading
)
)
)

PHP foreach with multidimensional array not printing all values

I have a very simple multidimensional array and some PHP code. The code should print the p_id values, but it does not do it. Do I really have to add one foreach more or is there other ways?
And here is the array:
Array (
[2764] => Array (
[status] => 0
[0] => Array (
[p_id] => 2895
)
[1] => Array (
[p_id] => 1468
)
)
[5974] => Array (
[status] => 0
[0] => Array (
[p_id] => 145
)
[1] => Array (
[p_id] => 756
)
)
)
Here is my PHP code:
foreach($arr as $innerArray)
foreach($innerArray as $key => $value)
echo $key . "=>" . $value . "<br>";
It prints:
status=>0
0=>Array
1=>Array
status=>0
0=>Array
1=>Array
foreach($arr as $a => $a_value)
{
echo $a . '<br>';
foreach($a_value as $av_arr => $av)
{
if(!is_array($av))
{
echo $av_arr . '=>' . $av . '<br>';
}
else
{
foreach($av as $inner_av => $inner_av_val)
{
echo $inner_av . '=>' . $inner_av_val . '<br>';
}
}
}
}
This simple call to array_walk_recursive() produces the output requested in the question:
array_walk_recursive(
$arr,
function ($value, $key) {
echo $key . "=>" . $value . "<br>";
}
);
But it doesn't make much sense as the output mixes the values of status with the values of p_id.
I would go for a more structured display using the original code with a little more meaning for the names of the variables:
foreach ($arr as $catId => $catInfo) {
// Category ID and details; use other names if I'm wrong
printf("Category: %d (status: %s)\n", $catId, $catInfo['status'] ? 'active' : 'inactive');
foreach ($catInfo as $key => $value) {
if ($key == 'status') {
// Ignore the status; it was already displayed
continue;
}
foreach ($value as $prodInfo) {
printf(" Product ID: %d\n", $prodInfo['p_id']);
}
}
}
The structure of the input array tells me you should first fix the code that generates it. It should group all the products (the values that are now indexed by numeric keys) into a single array. It should look like this:
$input = array(
'2764' => array(
'status' => 0,
'products' => array(
2895 => array(
'p_id' => 2895,
'name' => 'product #1',
// more product details here, if needd
),
1468 => array(
'p_id' => 1468,
'name' => 'product #2',
),
// more products here
),
// more categories here
),
Then the code that prints it will look like this:
foreach ($arr as $catId => $catInfo) {
// Category ID and details; use other names if I'm wrong
printf("Category: %d (status: %s)\n", $catId, $catInfo['status'] ? 'active' : 'inactive');
foreach ($catInfo['products'] as $prodInfo) {
printf(" %s (ID: %d)\n", $prodInfo['name'], $prodInfo['p_id']);
// etc.
}
}
Use a recursive function:
function printIds($arr) {
foreach ($arr as $key => $val) {
if (is_array($val) && array_key_exists("p_id", $val)) {
echo $val["p_id"]."\n";
} elseif(is_array($val)) {
printIds($val);
}
}
}
Working example:
$arr = [
2764 => [
'status' => 0,
['p_id' => 100],
],
4544 => [
'status' => 0,
['p_id' => 100],
],
['p_id' => 100],
];
function printIds($arr) {
foreach ($arr as $key => $val) {
if (is_array($val) && array_key_exists("p_id", $val)) {
echo $val["p_id"]"\n";
} elseif(is_array($val)) {
printIds($val);
}
}
}
printIds($arr);
The function loops all entries of a given array and echo's them out, if they contain an array with a key named "p_id". If it does find a nested array, then it does loop also all child arrays.

Add value to existing array key in foreach loop

I have the following bibliography data in an array (note that fields are in random order - there are others fields as well):
Array
(
[0] => Array
(
['Pub_Name'] => Nature
['Volume'] => 6
['Pages'] => 215-217
)
[1] => Array
(
['Volume'] => 15
['Pages'] => 358-360
['Pub_Name'] => Science
)
[2] => Array
(
['Pub_Name'] => PNAS
['Pages'] => 17-19
['Volume'] => 22
)
)
I want to "merge" those three fields into one, for example ['Pub_Name']=Nature, 6: 215-217. I tried the following whitout success (I guess $Record['Pub_Name'] is the incorrect sintax):
foreach ($MyArray as $Record) {
foreach ($Record as $key => $values) {
if ($key=="Volume") {$Volumen=", ".$values;} else {$Volumen="";}
if ($key=="Pages") {$Paginas=": ".$values;} else {$Paginas="";}
}
//This is the line for which I want to know the sintax!!
$Record['Pub_Name'].=$Volumen.$Paginas;
}
No need for two loops:
foreach ($MyArray as $Record) {
$result[]['Pub_Name'] = "{$Record['Pub_Name']}, {$Record['Pages']}: {$Record['Volume']}";
}
Then you have the new Pub_Name entries in $result.
If you want to modify the original then reference & $Record:
foreach ($MyArray as &$Record) {
$Record['Pub_Name'] = "{$Record['Pub_Name']}, {$Record['Pages']}: {$Record['Volume']}";
}
Or use the key and modify the original array:
foreach ($MyArray as $key => $Record) {
$MyArray[$key]['Pub_Name'] = "{$Record['Pub_Name']}, {$Record['Pages']}: {$Record['Volume']}";
}
PHP code demo
<?php
$array=Array
(
0 => Array
(
'Pub_Name' => "Nature",
'Volume' => 6,
'Pages' => "215-217"
),
1 => Array
(
'Volume' => 15,
'Pages' => "358-360",
'Pub_Name' => "Science"
),
2 => Array
(
'Pub_Name' => 'PNAS',
'Pages' => "17-19",
'Volume' => 22
)
);
$result=array();
foreach ($array as $data)
{
$result[]=array('Pub_Name'=> $data['Pub_Name'].", ".$data["Volume"].": ".$data["Pages"]);
}
print_r($result);
Output:
Array
(
[0] => Array
(
[Pub_Name] => Nature, 6: 215-217
)
[1] => Array
(
[Pub_Name] => Science, 15: 358-360
)
[2] => Array
(
[Pub_Name] => PNAS, 22: 17-19
)
)
I guess this is what you are looking for:
<?php
$input = [
[
'Pub_Name' => 'Nature',
'Volume' => '6',
'Pages' => '215-217'
],
[
'Volume' => '15',
'Pages' => '358-30',
'Pub_Name' => 'Science',
],
[
'Pub_Name' => 'PNAS',
'Pages' => '17-19',
'Volume' => '22'
]
];
$output = [];
array_walk($input, function ($entry) use (&$output) {
$output[] = sprintf(
'%s, %s: %s',
$entry['Pub_Name'],
$entry['Volume'],
$entry['Pages']
);
});
print_r($output);
The output of above code obviously is:
Array
(
[0] => Nature, 6: 215-217
[1] => Science, 15: 358-30
[2] => PNAS, 22: 17-19
)
Use array_map
$in = [
0 => [
'Pub_Name' => 'Nature',
'Volume' => 6,
'Pages' => '215-217'
],
1 => [
'Volume' => 15,
'Pages' => '358-360',
'Pub_Name' => 'Science',
],
2 => [
'Pub_Name' => 'PNAS',
'Pages' => '17-19',
'Volume' => 22
]
];
array_map(function ($item) {
return $item['Pub_Name'] . ', ' . $item['Volume'] . ': ' . $item['Pages'];
}, $in);
There are a few different ways to do this - but one of the more readable ways:
// create a copy of the original - so we aren't looping thru the same array we're updating
$updatedArray = $MyArray;
foreach ($MyArray as $index => $record) {
$updatedArray[$index]['Pub_Name'] =
$record['Pub_Name'].
($record['Volume'] ? ', '.$record['Volume'] : '').
($record['Pages'] ? ': '.$record['Pages']:'');
}
Clear way in a single loop. Use sprintf() for easy formatting:
<?php
$src =[ ['Pub_Name' => 'Nature', 'Volume' => '6', 'Pages' => '215-217'],
['Volume' => '15', 'Pages' => '358-30', 'Pub_Name' => 'Science'],
['Pub_Name' => 'PNAS', 'Pages' => '17-19', 'Volume' => '22']
];
foreach ($src as $element) {
$dest[] = sprintf("%s, %d: %s",
$element['Pub_Name'],
$element['Volume'],
$element['Pages']);
}
var_dump($dest);
?>
And you get:
array(3) {
[0]=> string(18) "Nature, 6: 215-217"
[1]=> string(19) "Science, 15: 358-30"
[2]=> string(15) "PNAS, 22: 17-19"
}
Test it here.
This should help:
$combined = [];
foreach($myArray as $pub) {
$combined.push($pub['Pub_Name'] . ', ' . $pub['Volume'] . ': ' . $pub['Pages']);
}

Matching an array value by key in PHP

I have an array of items:
array(
[0] => array(
'item_no' => 1
'item_name' => 'foo
)
[1] => array(
'item_no' => 2
'item_name' => 'bar'
)
) etc. etc.
I am getting another array from a third party source and need to remove items that are not in my first array.
array(
[0] => array(
'item_no' => 1
)
[1] => array(
'item_no' => 100
) # should be removed as not in 1st array
How would I search the first array using each item in the second array like (in pseudo code):
if 'item_no' == x is in 1st array continue else remove it from 2nd array.
// Returns the item_no of an element
function get_item_no($arr) { return $arr['item_no']; }
// Arrays of the form "item_no => position in the array"
$myKeys = array_flip(array_map('get_item_no', $myArray));
$theirKeys = array_flip(array_map('get_item_no', $theirArray));
// the part of $theirKeys that has an item_no that's also in $myKeys
$validKeys = array_key_intersect($theirKeys, $myKeys);
// Array of the form "position in the array => item_no"
$validPos = array_flip($validKeys);
// The part of $theirArray that matches the positions in $validPos
$keptData = array_key_intersect($theirArray, $validPos);
// Reindex the remaining values from 0 to count() - 1
return array_values($keptData);
All of this would be easier if, instead of storing the key in the elements, you stored it as the array key (that is, you'd be using arrays of the form "item_no => item_data") :
// That's all there is to it
return array_key_intersect($theirArray, $myArray);
You can also do:
$my_array =array(
0 => array( 'item_no' => 1,'item_name' => 'foo'),
1 => array( 'item_no' => 2,'item_name' => 'bar')
);
$thrid_party_array = array(
0 => array( 'item_no' => 1),
1 => array( 'item_no' => 100),
);
$temp = array(); // create a temp array to hold just the item_no
foreach($my_array as $key => $val) {
$temp[] = $val['item_no'];
}
// now delete those entries which are not in temp array.
foreach($thrid_party_array as $key => $val) {
if(!in_array($val['item_no'],$temp)) {
unset($thrid_party_array[$key]);
}
}
Working link
If your key is not actually a key of your array but a value, you will probably need to do a linear search:
foreach ($itemsToRemove as $itemToRemove) {
foreach ($availableItems as $key => $availableItem) {
if ($itemToRemove['item_no'] === $availableItem['item_no']) {
unset($availableItems[$key]);
}
}
}
It would certainly be easier if item_no is also the key of the array items like:
$availableItems = array(
123 => array(
'item_no' => 123,
'item_name' => 'foo'
),
456 => array(
'item_no' => 456,
'item_name' => 'bar'
)
);
With this you could use a single foreach and delete the items by their keys:
foreach ($itemsToRemove as $itemToRemove) {
unset($availableItems[$itemToRemove['item_no']]);
}
You could use the following to build an mapping of item_no to your actual array keys:
$map = array();
foreach ($availableItems as $key => $availableItem) {
$map[$availableItems['item_no']] = $key;
}
Then you can use the following to use the mapping to delete the corresponding array item:
foreach ($itemsToRemove as $itemToRemove) {
unset($availableItems[$map[$itemToRemove['item_no']]]);
}

Categories