aray_combine not working as expected - php

I expect array_combine to be able to take two arrays such as:
array('sample', 'sample_two', 'sample');
array(array('info', 'info_two'), array('bananas'), array('more_stuff'));
and produce:
array(
'sample' => array(
'info', 'info_two', 'more_stuff'
),
'sample_two' => array(
'bananas'
)
);
instead I get:
array(
'sample' => array(
'more_stuff'
),
'sample_two' => array(
'bananas'
)
);
Now I know php doesn't allow for duplicate key's so how can I use array_combine or some other method to achieve the desired array? It is safe to say that, the first array, will always match the second array in terms of layout. So you can draw lines between the values of array one and array two.

Why not writing your own function?
function my_array_combine(array $keys, array $values) {
$result = array();
for ($i = 0; $i < count($keys); $i++) {
$key = $keys[$i];
if (!isset($result[$key])) {
$result[$key] = array();
}
$result[$key] = array_merge($result[$key], $values[$i]);
}
return $result;
}

Related

PHP : merge multiples arrays with common keys [duplicate]

This question already has answers here:
Merge two indexed arrays of indexed arrays based on first column value
(2 answers)
Closed 5 months ago.
I have 5 differents arrays in my script :
$array1 = array(
array( "id"=>"1", "title"=>"Batman" ),
array( "id"=>"2", "title"=>"Spiderman" ),
array( "id"=>"3", "title"=>"Titanic" ),
array( "id"=>"4", "title"=>"Dracula" ),
);
$array2 = array(
array( "id"=>"1", "releasedate"=>"1926" ),
array( "id"=>"2", "releasedate"=>"1956" ),
array( "id"=>"3", "releasedate"=>"2001" ),
array( "id"=>"4", "releasedate"=>"1982" ),
);
etc ...
As you see, info about movie number 1 is splitted on all the arrays (in fact -> 5 arrays). Then I would like to merge all my arrays to get something like this :
$array_FINAL = array(
array( "id"=>"1", "title"=>"Batman", "releasedate"=>"1926" ),
array( "id"=>"2", "title"=>"Spiderman", "releasedate"=>"1956" ),
array( "id"=>"3", "title"=>"Titanic", "releasedate"=>"2001" ),
array( "id"=>"4", "title"=>"Dracula", "releasedate"=>"1982" ),
);
I tried array_merge, array_combine, no good results. I also checked other topics on stackoverflow but no one help me (i may miss the one i need!)
Any help ? :)
EDIT : Sorry, i did would give a little more details ... rows in the arrays could be in misc. order, then according to my code example : the movie "Batman" can be in 1st row in the first array, but in the 3rd row in the second array...
If the order of both arrays is the same, you can simply use
$array_final = array_replace_recursive($array1, $array2);
However, if you want to merge them by the "id", you need to loop through them. A solution with the complexity O(m*n):
$array_final = array();
// loop through all movies in array1
foreach($array1 as $movie){
foreach($array2 as $movie_release) {
if ($movie['id'] == $movie_release['id']) {
$movie['releasedate'] = $movie_release['releasedate'];
break;
}
}
$array_final[] = $movie;
}
And a little less complex O(m+n):
// create arrays with the ID as key
$titles = array_column($array1, 'title', 'id');
$releasedates = array_column($array2, 'releasedate', 'id');
$array_final = array();
foreach($titles as $id => $title) {
$array_final[] = array(
'id' => $id,
'title' => $title,
'releasedate' => $releasedates[$id]
);
}
One of the solutions is:
$array1 = array(
array( "id"=>"1", "title"=>"Batman" ),
array( "id"=>"2", "title"=>"Spiderman" ),
array( "id"=>"3", "title"=>"Titanic" ),
array( "id"=>"4", "title"=>"Dracula" ),
);
$array2 = array(
array( "id"=>"1", "releasedate"=>"1926" ),
array( "id"=>"2", "releasedate"=>"1956" ),
array( "id"=>"3", "releasedate"=>"2001" ),
array( "id"=>"4", "releasedate"=>"1982" ),
);
// here we create pairs `id => releasedate`
$new_array2 = [];
foreach ($array2 as $v) {
$new_array2[$v['id']] = $v['releasedate'];
}
foreach ($array1 as &$value) {
// here we try to find key `$value['id']` in `$new_array2`
// and get it's value
if (isset($new_array2[$value['id']])) {
$value['releasedate'] = $new_array2[$value['id']];
}
}
If you're 100% sure that orders of ids are the same in both arrays you can just:
$i = 0;
foreach ($array1 as &$value) {
$value['releasedate'] = $array2[$i]['releasedate'];
$i++;
}
See this code prototype (it is simple and don't need to explanations I believe):
$fArr = [];
for ( $i = 1; $i <= 4; $i++ ) {
$fArr[] = [
'id' => $i,
'title' => $array1[$i - 1]['title'],
'releasedate' => $array2[$i - 1]['releasedate'],
];
}
Sandbox code example
Assuming all of your five arrays contain the id key, you can do this with a nested foreach loop.
foreach (array_merge($array1, $array2, $array3, $array4, $array5) as $item) {
foreach ($item as $key => $value) {
$result[$item['id']][$key] = $value;
}
}
The outer foreach iterates all the rows in all the arrays. The inner one loops over each column and assigns its value to the corresponding key in the result array.

Loop over one array as if it was a multidimensional array

I have an array like:
$array = array(
'name' => 'Humphrey',
'email' => 'humphrey#wilkins.com
);
This is retrieved through a function that gets from the database. If there is more than one result retrieved, it looks like:
$array = array(
[0] => array(
'name' => 'Humphrey1',
'email' => 'humphrey1#wilkins.com'
),
[1] => array(
'name' => 'Humphrey2',
'email' => 'humphrey2#wilkins.com'
)
);
If the second is returned, I can do a simple foreach($array as $key => $person), but if there is only one result returned (the first example), I can't run a foreach on this as I need to access like: $person['name'] within the foreach loop.
Is there any way to make the one result believe its a multidimensional array?
Try this :
if(!is_array($array[0])) {
$new_array[] = $array;
$array = $new_array;
}
I would highly recommended making your data's structure the same regardless of how many elements are returned. It will help log terms and this will have to be done anywhere that function is called which seems like a waste.
You can check if a key exists and do some logic based on that condition.
if(array_key_exists("name", $array){
//There is one result
$array['name']; //...
} else {
//More then one
foreach($array as $k => $v){
//Do logic
}
}
You will have the keys in the first instance in the second yours keys would be the index.
Based on this, try:
function isAssoc(array $arr)
{
if (array() === $arr) return false;
return array_keys($arr) !== range(0, count($arr) - 1);
}
if(isAssoc($array)){
$array[] = $array;
}
First check if the array key 'name' exists in the given array.
If it does, then it isn't a multi-dimensional array.
Here's how you can make it multi-dimensional:
if(array_key_exists("name",$array))
{
$array = array($array);
}
Now you can loop through the array assuming it's a multidimensional array.
foreach($array as $key => $person)
{
$name = $person['name'];
echo $name;
}
The reason of this is probably because you use either fetch() or fetchAll() on your db. Anyway there are solutions that uses some tricks like:
$arr = !is_array($arr[0]) ? $arr : $arr[0];
or
is_array($arr[0]) && ($arr = $arr[0]);
but there is other option with array_walk_recursive()
$array = array(
array(
'name' => 'Humphrey1',
'email' => 'humphrey1#wilkins.com'
),
array(
'name' => 'Humphrey2',
'email' => 'humphrey2#wilkins.com'
)
);
$array2 = array(
'name' => 'Humphrey2',
'email' => 'humphrey2#wilkins.com'
);
$print = function ($item, $key) {
echo $key . $item .'<br>';
};
array_walk_recursive($array, $print);
array_walk_recursive($array2, $print);

Searching an array of associate arrays for two matching parameters

I have a loop that builds an array of associative arrays that looks like this:
array(
'foo' => '',
'bar' => '',
'thingys' => array()
)
on each iteration of the loop, I want to search through the array for an associate array that's 'foo' and 'bar' properties match those of the current associate array. If it exists I want to append the thingys property of the current associative array to the match. Otherwise append the entire thing.
I know how to do this with for loops, but I'm wondering if there is a simpler way to do this with an array function. I'm on php 5.3.
Example
<?php
$arr = array(
array(
'foo' => 1,
'bar' => 2,
'thing' => 'apple'
),
array(
'foo' => 1,
'bar' => 2,
'thing' => 'orange'
),
array(
'foo' => 2,
'bar' => 2,
'thing' => 'apple'
),
);
$newArr = array();
for ($i=0; $i < count($arr); $i++) {
$matchFound = false;
for ($j=0; $j < count($newArr); $j++) {
if ($arr[$i]['foo'] === $newArr[$j]['foo'] && $arr[$i]['bar'] === $newArr[$j]['bar']) {
array_push($newArr[$j]['thing'], $arr[$i]['things']);
$matchFound = true;
break;
}
}
if (!$matchFound) {
array_push($newArr,
array(
'foo' => $arr[$i]['foo'],
'bar' => $arr[$i]['bar'],
'things' => array($arr[$i]['thing'])
)
);
}
}
/*Output
$newArr = array(
array(
'foo' => 1,
'bar' => 2,
'things' => array('orange', 'apple')
),
array(
'foo' => 2,
'bar' => 2,
'things' => array('apple')
),
)
*/
?>
I don't know if it is possible through a built-in function, but I think no. Something can be implemented through array_map, but anyway you have to perform a double loop.
I propose you a one-loop solution using a temporary array ($keys) as index of already created $newArr items, based on foo and bar; elements of original array are processed through a foreach loop, and if a $keys element with first key as foo value and second key as bar value exists, then the current thing value is added to the returned key index of $newArr, otherwise a new $newArray element is created.
$newArr = $keys = array();
foreach( $arr as $row )
{
if( isset( $keys[$row['foo']][$row['bar']] ) )
{ $newArr[$keys[$row['foo']][$row['bar']]]['thing'][] = $row['thing']; }
else
{
$keys[$row['foo']][$row['bar']] = array_push( $newArr, $row )-1;
$newArr[$keys[$row['foo']][$row['bar']]]['thing'] = array( $row['thing'] );
}
}
unset( $keys );
3v4l.org demo
Edit: array_map variant
This is the same solution above, using array_map instead of foreach loop. Note that also your original code can be converted in this way.
$newArr = $keys = array();
function filterArr( $row )
{
global $newArr, $keys;
if( isset( $keys[$row['foo']][$row['bar']] ) )
{ $newArr[$keys[$row['foo']][$row['bar']]]['thing'][] = $row['thing']; }
else
{
$keys[$row['foo']][$row['bar']] = array_push( $newArr, $row )-1;
$newArr[$keys[$row['foo']][$row['bar']]]['thing'] = array( $row['thing'] );
}
}
array_map( 'filterArr', $arr );
3v4l.org demo

Loop through a multi dimensional array checking a specific key for repeat values in PHP

I have a multi dimensional array that I have got from a database and I want to check this array for duplicate data and store it in another array of duplicates. my code is as follows
//create temp array
$tmp = array();
foreach ($matchingarray as $nameKey => $match) {
// loop through and stoe the contents of that array to another so i can compare
$tmp[] = $match;
}
// create an array to store duplicates
$duplicatesArray = array();
// if the temp array is not empty then loop through both arrays
if (! empty($tmp)) {
foreach ($tmp as $key => $tmpvalue) {
foreach ($matchingarray as $key => $match) {
// if a key name is the same in both arrays then add it tothe duplicates array
if ($tmpvalue['name'] == $match['name']) {
$duplicatesArray = $match;
}
}
}
}
//count how many are duplicates
$dups = count($duplicatesArray);
What I would like to know is this the right logic?
I will take where Igoel left off
there is 1 error and also 1 suggest that i will make.
Error:
you cannot reuse $key twice in the foreach because they will override.
Suggestion as what Igoel stated: your best bet for duplicate effectively is to use sql. SQL is faster at processing than looping through arrays. Don't forget you need to load the data into memory and thats costly.
Try this way
<?php
static $cnt = array();
$min = 1;
$coll = array(
'dep1' => array(
'fy' => array('john', 'johnny', 'victor'),
'sy' => array('david', 'arthur'),
'ty' => array('sam', 'joe', 'victor')
),
'dep2' => array(
'fy' => array('natalie', 'linda', 'molly'),
'sy' => array('katie', 'helen', 'sam', 'ravi', 'vipul'),
'ty' => array('sharon', 'julia', 'maddy')
)
);
function recursive_search(&$v, $k){
global $cnt;
$cnt[] = $v;
}
array_walk_recursive($coll, 'recursive_search');
$newNumbers = array_filter(
array_count_values($cnt),
function ($value) use($min) {
return ($value > $min);
}
);
echo "Values > 1 are repeated \n";
print_r(array_count_values($cnt));
echo "Values repeted\n";
print_r($newNumbers);
DEMO

Joining rows from two 2d arrays where a common column value is found

I have two arrays that I would like to join into one. Both arrays have a common key=>value and I would like to insert the values of one array to the other so that I to create one array.
$array1 = [
['ID' => 123456, 'Key' => 1000, 'value' => 123.45],
['ID' => 789012, 'Key' => 1001, 'value' => 56748.17],
];
$array2 = [
['Key' => 1000, 'description' => 'desc1'],
['Key' => 1001, 'description' => 'desc2'],
];
I would like to join Array2 with Array1 so that the resulting Array is as follows:
array (
0 =>
array (
'ID' => 123456,
'Key' => 1000,
'value' => 123.45,
'description' => 'desc1',
),
1 =>
array (
'ID' => 789012,
'Key' => 1001,
'value' => 56748.17,
'description' => 'desc2',
),
)
So the arrays have been joined using the [Key] value as the, well, key. I've looked at array_merge and other function but I can't seem to get these two arrays to "merge" properly.
try this, its linear
$keyval = array();
foreach($array1 as $item)$keyval[$item['Key']] = $item['value'];
foreach($array2 as $key=>$item)$array2[$key]['description'] = isset($keyval[$item['Key']]) ? $keyval[$item['Key']] : '';
You would have to do something like
$result = array();
foreach ($a1 as $v1)
{
foreach ($a2 as $k2 => $v2)
{
if ($v1['Key'] === $v2['Key'])
{
$result[] = array_merge($v1, $v2);
unset($a2[$k2]);
break;
}
}
}
Version with for loops
$result = array();
$c_a1 = count($a1);
$c_a2 = count($a2);
for ($i = 0; $i < $c_a1; $i++)
{
for ($j = 0; $j < $c_a2; $j++)
{
if ($a1[$i]['Key'] === $a2[$j]['Key'])
{
$result[] = array_merge($a1[$i], $a2[$j]);
unset($a2[$j]);
$c_a2--;
break;
}
}
}
This is my approach:
$temp_ array = array_fill_keys (array_map(create_function('$a', 'return $a["Key"];'), $array_1) , $array_1);
$result = array();
foreach ($array_2 as $item) {
if (isset($temp_array[$item['Key']])) {
$result[] = array_merge($item, $temp_array[$item['Key']]);
}
}
I have elaborated more in the code above, and reached this improved version:
function array_merge_items_by_common_key_value($key, $array_1, $array_2)
{
$result = array();
$temp_ array = array_fill_keys(array_map(create_function('$a', 'return $a["' . $key . '"];'), $array_1) , $array_1);
foreach ($array_2 as $item)
{
$result[$item[$key]] = isset($temp_array[$item[$key]]) ? array_merge($item, $temp_array[$item[$key]]) : $item;
}
return array_values(array_merge($result, array_diff_key($array_1, $result)));
}
$merged_arrays = array_merge_items_by_common_key_value('Key', $temp_array, $array_2);
First, a temporary array is created: it is equal to $array_1, but its keys are the values to be matched.
Then, $array_2 is looped. When a match is found, the merge is done. If there is no match, then the $array_2 value is maintained, untouched.
Finally, those values in the $array_1 which were not matched, are also appended to the resulting array.
So, no item of both $array_1 or $array_2 is lost, while the matched items are merged.
#radashk's solution will work if you can always guarantee that $array1[$i] corresponds to $array2[$i]. From my reading of the question, that's not guaranteed, but instead you want to make sure that $array1[$i]['Key'] == $array2[$j]['Key'], and combine elements where those Keys match.
There may be a more elegant solution, but I would do it like this:
// builds up new $tmpArray, using the Key as the index
$tmpArray = array();
foreach($array1 as $innerArray1){
$tmpArray[$innerArray1['Key']] = $innerArray1;
}
//Merges the values from $array2 into $tmpArray
foreach($array2 as $innerArray2) {
if (isset($tmpArray[$innerArray2['Key']])) {
$tmpArray[$innerArray2['Key']] = array_merge($tmpArray[$innerArray2['Key']], $innerArray2);
}else{
$tmpArray[$innerArray2['Key']] = $innerArray2;
}
}
Use temporary first level keys to swiftly identify matching Key values between the two arrays. When an array2 row qualifies for merger with the first, use the union-assignment operator (+=). Call array_value() after looping if you don't want to preserve the temporary keys.
Code: (Demo)
$result = array_column($array1, null, 'Key');
foreach ($array2 as $row) {
if (isset($result[$row['Key']])) {
$result[$row['Key']] += $row;
}
}
var_export(array_values($result));

Categories