Merge array with varying key value pairs - php

So I have various arrays which do not always have the same key/value pairs in them. What I want to do is to be able to merge the arrays, but to add in empty key/value pairs if they don't already exist in that array, but do in others. It's hard to explain but this might explain it better:
$arrayOne = array('name' => 'rory', 'car' => 'opel');
$arrayTwo = array('name' => 'john', 'dog' => 'albert');
I need to somehow turn this into:
$finalArray = array(
array('name' => 'rory', 'car' => 'opel', 'dog' => ''),
array('name' => 'john', 'car' => '', 'dog' => 'albert')
);
I have been looking through PHP's documentation but can't find anything that will do this for me. Can anyone point me in the right direction? I don't even know an appropriate search term for what I want to achieve here, "array merge" isn't specific enough.

<?php
$arrayOne = array('name' => 'rory', 'car' => 'opel');
$arrayTwo = array('name' => 'john', 'dog' => 'albert');
$diff1=array_diff(array_flip($arrayOne), array_flip($arrayTwo));
$diff2=array_diff(array_flip($arrayTwo), array_flip($arrayOne));
//array_flip flips the key of array with value
//array_diff would return the values in the first array that are not present in any of the other arrays inside
foreach ($diff2 as $s) {
$arrayOne[$s]="";
}
foreach ($diff1 as $s) {
$arrayTwo[$s]="";
};
//set key that didn't exist in that array as ""
$finalArray[]=$arrayOne;
$finalArray[]=$arrayTwo;
//add the arrays to the final array
print_r($finalArray);

Here's what I would do:
Merge your separate arrays into one (into a temporary var) using array_merge
Get the unique keys of this new array using array_keys
For each separate array, loop through the new keys array and add an empty value for each key that is not in the array. Then push the separate array into a final array.

<?php
$arrayOne = array('name' => 'rory', 'car' => 'opel');
$arrayTwo = array('name' => 'john', 'dog' => 'albert');
$new = array_merge($arrayOne,$arrayTwo);
$new = array_keys($new);
$newarray = array();
foreach($new as $value){
$newarray[0][$value] = isset($arrayOne[$value]) ? $arrayOne[$value] : '' ;
$newarray[1][$value] = isset($arrayTwo[$value]) ? $arrayTwo[$value] : '' ;
}
echo "<pre>";print_r($newarray);
You can also use this short answer
$arrayOne = array('name' => 'rory', 'car' => 'opel');
$arrayTwo = array('name' => 'john', 'dog' => 'albert');
$defaults = array('name' => '','car' => '','dog' => '');
$arrayOne += $defaults;
$arrayTwo += $defaults;
$newarray = array($arrayOne,$arrayTwo);
echo "<pre>";print_r($newarray);

Basing on what Justin Powell outlined, I managed to come up with this code before the other two code examples were posted (thank you mamta & user6439245).
I also needed to take the keys containing numbers and sort them appropriately, otherwise my keys would've been indexed like employer_1, education_1, employer_2, education_2.
// get the initial form entries data
$entries = array(
array('name' => 'john', 'car' => 'fiat', 'employer_1' => 'tangerine', 'education_1' => 'hideaways', 'education_2' => 'extras'),
array('name' => 'rory', 'car' => 'opel', 'employer_1' => 'sagittarius', 'employer_2' => 'tangerine', 'employer_3' => 'thehideout', 'education_1' => 'knatchbull')
);
// create an empty array to populate with all field keys
$mergedKeys = array();
// push all field keys into the array
foreach($entries as $entry){
foreach($entry as $key => $value){
array_push($mergedKeys, $key);
}
}
// remove duplicate keys from the array
$uniqueMergedKeys = array_unique($mergedKeys);
// create a new array to populate with the field keys we need to sort - the ones with numbers in
$keysToSort = array();
// push the number-containing keys into the array
$i=0;
foreach($uniqueMergedKeys as $uniqueKey){
if(1 === preg_match('~[0-9]~', $uniqueKey)){
array_push($keysToSort, $uniqueKey);
}
$i++;
}
// remove the number containing keys from the unique keys array
$uniqueMergedKeys = array_diff($uniqueMergedKeys, $keysToSort);
// sort the keys that need sorting
sort($keysToSort);
// put the newly sorted keys back onto the original keys array
foreach($keysToSort as $key){
array_push($uniqueMergedKeys, $key);
}
$final = array();
$i = 0;
foreach($entries as $entry){
foreach($uniqueMergedKeys as $key){
//if($entries[$i][$key]){
if (array_key_exists($key, $entries[$i])) {
$final[$i][$key] = $entries[$i][$key];
} else {
$final[$i][$key] = '';
}
}
$i++;
}
echo '<pre>'; print_r($final); echo '</pre>';

Related

Check if array doesn't have a key and create it dynamically

I need to check if the keys of an array match an array of keys, and if they don't match then they need to be created. While I managed to create the check I still need to return all keys that don't match in the in_array condition so that they can be added to the original array. How can I achieve this?
My current code:
$new_value = ['id','name','age'];
$keys = ['id','name','age','sex','height','weight'];
foreach($new_value as $new_value){
if(!in_array($new_value, $keys )){
$new_value["{$key}"] = '';
}
}
The desired result would be:
Array pre processing:
'id' => 1,
'name' => 'Ed',
'age' => 15,
Array post processing:
'id' => 1,
'name' => 'Ed',
'age' => 15,
'sex' => '',
'height' => '',
'weight' => '',
So, there are a couple of things here.
// When you are running through your foreach, you don't want to overwrite your
// array variable with the value, which is what is happening. Switch this to `new_values` (plural)
$new_values = ['id','name','age'];
$keys = ['id','name', 'age','sex','height','weight'];
// Since $keys is your desired structure, we want to loop through $key rather than $new_values, and add any missing keys to the $new_values
foreach($keys as $key){
// We want to check if $new_values has all the $keys (you were checking if $keys had all of $new_values, which it does already
if(!in_array($key, $new_values )){
// Since $key is already a string, we don't need to place it in quotes, just put the variable directly into the array as a new array item (because you are using an array of strings, the keys will be numerical)
$new_values[] = $key
}
}
If you are looking for a keyed array, so that you can get the value of $new_values['name'], then you will need to set your arrays up differently and do your checks differently. You can also use $keys to hold a default value.
// Set the keys for your array, instead of having an array of strings that is keyed numerically
$new_values = ['id' => 'user_id','name' => 'user name','age' => 'user age'];
$keys = ['id' => 'default_value','name' => 'default_value', 'age' => 'default_value','sex' => 'default_value','height' => 'default_value','weight' => 'default_value'];
// Here we'll get the key and value of each item in the $keys array
foreach($keys as $key => $default) {
// Check if the array key exists in new values and if not, set it to the predefined default value
if(!array_key_exists($key, $new_values) {
$new_values[$key] = $default;
}
}
EDIT
As per one of the comments on the answer, you could further simplify this with array_merge. If you want to throw an error or do something special on each field, you could use the loop. If you just want to fill in the blanks, it would work like:
// Set the keys for your array, instead of having an array of strings that is keyed numerically
$new_values = ['id' => 'user_id','name' => 'user name','age' => 'user age'];
$keys = ['id' => 'default_value','name' => 'default_value', 'age' => 'default_value','sex' => 'default_value','height' => 'default_value','weight' => 'default_value'];
// If you aren't going to be using the original $new_values array for anything, you can just overwrite it.
// As stated in the comment below, $new_values should be the second value, keys that are in both arrays will be overwritten by what's in the second array.
$new_values = array_merge($keys, $new_values);
// If you will be using the original $new_values array later in the code, you can set the output to a new variable
$filled_values = array_merge($keys, $new_values);
I'm not sure, but you can try next code:
<?php
$data = [
"id" => 1,
"name" => "Ed",
"age" => 15,
];
$keys = ["id", "name", "age", "sex", "height", "weight"];
$result = array_reduce(
$keys,
function ($data, $key) {
if (!isset($data[$key])) $data[$key] = '';
return $data;
},
$data
);
var_export($result);
PHP sandbox here

PHP - array key within array value

I have a PHP array like this:
$arr = array(
'id' => 'app.settings.value.id',
'title' => 'app.settings.value.title',
'user' => 'app.settings.value.user'
);
I want to remove '.id', '.title' and '.user' in the array values. I want to insert the key of this array at the end of the value. I know, that I can get an array key by passing an array and a value to 'array_search', but I want the key within this one array definition - at the end of it's value. Is this possible?
I don't like this, but I guess it's simple and works:
$arr = array(
'id' => 'app.settings.value',
'title' => 'app.settings.value',
'user' => 'app.settings.value'
);
$result = array();
foreach ($arr AS $key => $value) {
$result[$key] = $value . '.' . $key;
}
You're storing app.settings.value which is the same for all array items, so personally I'd prefer:
$arr = array(
'id',
'title',
'user'
);
function prepend_key($key)
{
return 'app.settings.value.' . $key;
}
$result = array_map('prepend_key', $arr);
With $result containing:
array(
'app.settings.value.id',
'app.settings.value.title',
'app.settings.value.user'
);
At the end of the day, either works :)

Switch keys and value and Preserve entries with no value

I have this array:
'tab1' => '',
'tab2' => '',
'tab3' => 'active'
I want to do array_flip to swap the keys with the values, but the entries with an empty value are not kept.
How do I let PHP assign integer keys for me (like with an indexed array)?
Thanks
Edit:
To clarify things a bit, this is what I want:
0 => 'tab1'
1 => 'tab2'
'active' => 'tab3'
Directly through array_flip it's not possible. I think you want like this:-
<?php
$array1 = array('tab1' => '','tab2' => '','tab3' => 'active');
$array2 = array();
foreach($array1 as $key =>$value){
if(empty($value)){ // Or $value ==''
$array2[] = $key;
}else{
$array2[$value] = $key;
}
}
echo "<pre/>";print_r($array2);die;
?>
Output:- http://prntscr.com/79ge6z

php remove object from array of objects

I'm trying to remove an object from an array of objects by its' index. Here's what I've got so far, but i'm stumped.
$index = 2;
$objectarray = array(
0=>array('label'=>'foo', 'value'=>'n23'),
1=>array('label'=>'bar', 'value'=>'2n13'),
2=>array('label'=>'foobar', 'value'=>'n2314'),
3=>array('label'=>'barfoo', 'value'=>'03n23')
);
//I've tried the following but it removes the entire array.
foreach ($objectarray as $key => $object) {
if ($key == $index) {
array_splice($object, $key, 1);
//unset($object[$key]); also removes entire array.
}
}
Any help would be appreciated.
Updated Solution
array_splice($objectarray, $index, 1); //array_splice accepts 3 parameters
//(array, start, length) removes the given array and then normalizes the index
//OR
unset($objectarray[$index]); //removes the array at given index
$reindex = array_values($objectarray); //normalize index
$objectarray = $reindex; //update variable
array_splice($objectarray, $index, 1);
//array_splice accepts 3 parameters (array, start, length) and removes the given
//array and then normalizes the index
//OR
unset($objectarray[$index]); //removes the array at given index
$reindex = array_values($objectarray); //normalize index
$objectarray = $reindex; //update variable
You have to use the function unset on your array.
So its like that:
<?php
$index = 2;
$objectarray = array(
0 => array('label' => 'foo', 'value' => 'n23'),
1 => array('label' => 'bar', 'value' => '2n13'),
2 => array('label' => 'foobar', 'value' => 'n2314'),
3 => array('label' => 'barfoo', 'value' => '03n23')
);
var_dump($objectarray);
foreach ($objectarray as $key => $object) {
if ($key == $index) {
unset($objectarray[$index]);
}
}
var_dump($objectarray);
?>
Remember, your array will have odd indexes after that and you must (if you want) reindex it.
$foo2 = array_values($objectarray);
in that case you won't need that foreach just unset directly
unset($objectarray[$index]);

Exploding and replacing one array field

So, I have an array that, for unrelated reasons, has one imploded field in itself. Now, I'm interested in exploding the string in that field, and replacing that field with the results of the blast. I kinda-sorta have a working solution here, but it looks clunky, and I'm interested in something more efficient. Or at least aesthetically pleasing.
Example array:
$items = array(
'name' => 'shirt',
'kind' => 'blue|long|L',
'price' => 10,
'amount' => 5);
And the goal is to replace the 'kind' field with 'color', 'lenght', 'size' fields.
So far I've got:
$attribs = array('color', 'lenght', 'size'); // future indices
$temp = explode("|", $items['kind']); // exploding the field
foreach ($items as $key => $value) { // iterating through old array
if ($key == 'kind') {
foreach ($temp as $k => $v) { // iterating through exploded array
$new_items[$attribs[$k]] = $v; // assigning new array, exploded values
}
}
else $new_items[$key] = $value; // assigning new array, untouched values
}
This should (I'm writing by heart, don't have the access to my own code, and I can't verify the one I just wrote... so if there's any errors, I apologize) result in a new array, that looks something like this:
$new_items = array(
'name' => 'shirt',
'color' => 'blue',
'lenght' => 'long',
'size' => 'L',
'price' => 10,
'amount' => 5);
I could, for instance, just append those values to the $items array and unset($items['kind']), but that would throw the order out of whack, and I kinda need it for subsequent foreach loops.
So, is there an easier way to do it?
EDIT:
(Reply to Visage and Ignacio - since reply messes the code up)
If I call one in a foreach loop, it calls them in a specific order. If I just append, I mess with the order I need for a table display. I'd have to complicate the display code, which relies on a set way I get the initial data.
Currently, I display data with (or equivalent):
foreach($new_items as $v) echo "<td>$v</td>\n";
If I just append, I'd have to do something like:
echo "<td>$new_items['name']</td>\n";
foreach ($attribs as $v) echo "<td>$new_items[$v]</td>\n";
echo "<td>$new_items['price']</td>\n";
echo "<td>$new_items['amount']</td>\n";
Associative arrays generally should not depend on order. I would consider modifying the later code to just index the array directly and forgo the loop.
Try this:
$items = array( 'name' => 'shirt', 'kind' => 'blue|long|L', 'price' => 10, 'amount' => 5);
list($items['color'], $items['lenght'], $items['size'])=explode("|",$items['kind']);
unset $items['kind'];
I've not tested it but it should work.
Associative arrays do not have an order, so you can just unset the keys you no longer want and then simply assign the new values to new keys.
one way
$items = array(
'name' => 'shirt',
'kind' => 'blue|long|L',
'price' => 10,
'amount' => 5);
$attribs = array('color', 'lenght', 'size');
$temp = explode("|", $items['kind']);
$s = array_combine($attribs,$temp);
unset($items["kind"]);
print_r( array_merge( $items, $s) );
This should retain the ordering because it splits the keys and values into two numerically ordered arrays and combines them at the end. It isn't more efficient, but the code is easier to read.
$kind_keys = array('color', 'length', 'size');
$kind_values = explode("|", $items['kind']);
$keys = array_keys($items);
$values = array_values($items);
$index = array_search('kind', $keys);
// Put the new keys/values in:
array_splice($keys, $index, 1, $kind_keys);
array_splice($values, $index, 1, $kind_values);
// combine the result into a new array:
$result = array_combine($keys, $values));

Categories