I have pairs of keys identified by their respective ID like this:
array(
'key_a_0' => $a,
'key_a_1' => $a,
'key_b_0' => $b,
'key_b_1' => $b
)
I need this structure:
array(
'0' => array(
'key_a' => $a,
'key_b' => $b
),
'1' => array(
'key_a' => $a,
'key_b' => $b
)
)
What would be the best way to achieve this?
Provided this is exactly how all the data is present as, and stays as, this would then be simple to amend into the format you require with a simple foreach loop.
$new = array();
foreach($data as $key => $variable){
list($name,$var,$index) = explode("_", $key);
$new[$index][$name . '_' . $var] = $variable;
}
This returns;
Array
(
[0] => Array
(
[key_a] => 5
[key_b] => 10
)
[1] => Array
(
[key_a] => 5
[key_b] => 10
)
)
Example
Ideally - you'd want to set your array structure at creation, as Dagon said.
The following should do the job. This assumes, however, that the initial array comes in a specific order and that order is what is expected within each nested array in the final array, and that the keys in the initial array are always in that format.
$a = 5;
$b = 10;
$aRawArray = array(
'key_a_0' => $a,
'key_a_1' => $a,
'key_b_0' => $b,
'key_b_1' => $b,
);
$aFormattedArray = array();
foreach ($aRawArray as $sKey => $mValue) {
$aKeyParts = explode('_', $sKey);
$sExtractedKey = $aKeyParts[2];
$sNewKey = $aKeyParts[0] . '_' . $aKeyParts[1];
if (!isset($aFormattedArray[$sExtractedKey])) {
$aFormattedArray[$sExtractedKey] = array();
}
$aFormattedArray[$sExtractedKey][$sNewKey] = $mValue;
}
var_dump($aFormattedArray);
Related
I want to combine several arrays into one, they are the result of a form post with an unknown number of elements, eg:
$ids = [53,54,55];
$names = ['fire','water','earth'];
$temps = [500,10,5];
What i want is to make a function that takes these arrays as an input and produces a single output, like
$elements = [['id'=>53,'name'=>'fire','temp'=>500] , ['id'=>54,'name'=>'water','temp'=>500] , ['id'=>55,'name'=>'earth','temp'=>500]]
I came up with the following solution:
function atg($array) {
$result = array();
for ($i=0;$i<count(reset($array));$i++) {
$newAr = array();
foreach($array as $index => $val) {
$newAr[$index] = $array[$index][$i];
}
$result[]=$newAr;
}
return $result;
}
It can be called like
$elements = atg(['id' => $ids, 'name' => $names, 'temp' => $temps]);
And it produces the right output. To me it seems a bit overly complicated though, and I'm sure this is a common problem in PHP for form posts, combining seperate fields into a single array per item. What would be a better solution?
You can loop through all of your 3 arrays at once with array_map(). There you can just return the new array with a value of each of the 3 arrays, e.g.
$result = array_map(function($id, $name, $temp){
return ["id" => $id, "name" => $name, "temp" => $temp];
}, $ids, $names, $temps);
Use below code:-
$ids = [53,54,55];
$names = ['fire','water','earth'];
$temps = [500,10,5];
$result = [];
foreach($ids as $k=>$id){
$result[$k]['id'] = $id;
$result[$k]['name'] =$names[$k];
$result[$k]['temp'] = $temps[0];
}
echo '<pre>'; print_r($result);
output:-
Array
(
[0] => Array
(
[id] => 53
[name] => fire
[temp] => 500
)
[1] => Array
(
[id] => 54
[name] => water
[temp] => 500
)
[2] => Array
(
[id] => 55
[name] => earth
[temp] => 500
)
)
If you are ok with a destructive solution, array_shift could do the trick :
$elements = array();
while (!empty($ids)) {
$elements[] = array(
'id' => array_shift($ids),
'name' => array_shift($names),
'temp' => array_shift($temps),
);
}
If you want to make a function, using the same arguments than your example, a solution could be
function atg($array) {
$elements = array();
while (!empty($array[0])) {
$new_element = array();
foreach ($array as $key_name => $array_to_shift) {
$new_element[$key_name] = array_shit($array_to_shift);
}
$elements[] = $new_element;
}
return $elements;
}
$result[$ids]['name'] = $names[0];
$result[$ids]['temp'] = $temps[0]
I have a basic function that takes two arrays and merges them based on key. It is meant to work with arrays that have different keys but ultimately the same number of items. The function works well. However, it only inputs two arrays at a time to merge.
How can I modify so it takes n number of arrays to merge?
PHP
protected function arrayMergeKeys( $a, $b )
{
$retArr = array();
// I used min(countA, countB) so there will be no errors on
// unbalanced array item counts.
for ( $i = 0; $i < min( count( $a ), count( $b ) ); $i++ ) {
$retArr[ $i ] = array_merge( $a[ $i ], $b[ $i ] );
} // for end
return $retArr;
}
Desired result is to call the function with three arrays: $merged_arrays = arrayMergeKeys($a, $b, $c);
Input
//$a
Array
(
[a] => 'new value'
[b] => 2
[c] => 3
)
//$b
Array
(
[1] => 'blah'
[2] => 'dud'
[3] => 697
)
//$c
Array
(
[pet] => 'dog'
[breed] => 'german shepher'
[age] => 100
)
Output
Array
{
[a] => 'new value'
[1] => 'blah'
[pet] => 'dog'
}
Array
{
[b] => 2
[2] => 'dud'
[breed] => 'german shepher'
}
Array
{
[c] => 3
[3] => 697
[age] => 100
}
Leaving your original function untouched you could do it like this:
function arrayMulitMergeKeys() {
$arrayArgs = func_get_args();
$c = count($arrayArgs);
$result = arrayArgs[0];
for($i = 1; $i < $c; $i++) {
$result = arrayMergeKeys($result, $arrayArgs[$i]);
}
return $result;
}
This can be optimized further please re-check it once again
function arrayMergeKeys()
{
$retArr = array();
$arrayArgs = func_get_args();
//print_r($arrayArgs);
$minCount = count($arrayArgs[0]);
foreach($arrayArgs as $array){
if($minCount > count($array)){
$minCount = count($array);
}
}
// I used min(countA, countB) so there will be no errors on
// unbalanced array item counts.
for ( $i = 0; $i < $minCount; $i++ ) {
foreach($arrayArgs as $array){
$iCount = count($array);
for($j=0; $j<=$iCount; $j++)
{
if($i==$j){
$arrayKeys = array_keys($array);
if(isset($arrayKeys[$i])){
$retArr[ $i ][$arrayKeys[$i]] = $array[$arrayKeys[$i]];
break;
}
}
}
}
} // for end
return $retArr;
}
$a = Array
(
'a' => 'new value',
'b' => 2,
'c' => 3
);
$b = array
(
'1' => 'blah',
'2' => 'dud',
'3' => 697
);
$c = array
(
'pet' => 'dog',
'breed' => 'german shepher',
'age' => 100
);
print_r(arrayMergeKeys($a, $b, $c));
Here's some pseudo code to point you in the right direction.
function mergeArrays(a, b, c)
arrays = []
shortestLength = min(a.len, b.len, c.len)
for i in [0 .. shortestLength - 1]
arrays[i] = [ a[i], b[i], c[i] ];
return arrays
If you're doing this as an exercise, I would suggest implementing the following also:
mergeArrays(arr) where arr is an array of arrays that need to be merged.
Haven't tested, but this should work
protected function arrayMergeKeys(...$arrs) {
$retArr = array();
// I used min(countA, countB) so there will be no errors on
// unbalanced array item counts.
$countArr = array();
foreach ($arrs as $arr) {
$countArr[] = count($arr);
}
$min = min($countArr);
for ( $i = 0; $i < $min; $i++ ) {
$mergeArr = array();
foreach ($arrs as $arr) {
$mergeArr[] = $arr[$i];
}
$retArr[ $i ] = array_merge( $mergeArr );
} // for end
return $retArr;
}
You can simply 'add' the arrays:
$a = array
(
'a' => 'new value',
'b' => '2',
'c' => '3'
);
//$b
$b = array
(
'1' => 'blah',
'2' => 'dud',
'3' => '697'
);
//$c
$c = array
(
'pet' => 'dog',
'breed' => 'german shepher',
'age' => 100
);
$result= $a+$b+$c;
print_r($result);
output
Array ( [a] => new value [b] => 2 [c] => 3 [1] => blah [2] => dud [3] => 697 [pet] => dog [breed] => german shepher [age] => 100 )
I have a problem I cannot fix. I have 2 arrays and a string. The first array contains the keys the second one should use. The first one is like this:
Array
(
[0] => foo
[1] => bar
[2] => hello
)
Now I need a PHP code that converts it to the second array:
Array
(
[foo] => Array
(
[bar] => Array
(
[hello] => MyString
)
)
)
The number of items is variable.
Can someone please tell me how to do this?
You should use references to solve this problem:
$a = array (0 => 'foo', 1 => 'bar', 2 => 'hello' );
$b = array();
$ptr = &$b;
foreach ($a as $val) {
$ptr[$val] = Array();
$ptr = &$ptr[$val];
}
$ptr = 'MyString';
var_dump($b);
All you need is :
$path = array(
0 => 'foo',
1 => 'bar',
2 => 'hello'
);
$data = array();
$t = &$data;
foreach ( $path as $key ) {
$t = &$t[$key];
}
$t = "MyString";
unset($t);
print_r($data);
See Live Demo
This is an interesting situation which I created a working function for, but wondering if I just anyone had any simpler methods for this.
I have the following multidimensional array:
$foo = array(
[0] => array(
'keys' => array(
'key1' => 1,
'key2' => a,
'key3' => 123
),
'values' => array(
//goodies in here
)
)
[1] => array(
'keys' => array(
'key1' => 1,
'key2' => b,
'key3' => 456
),
'values' => array(
//goodies in here
)
)
)
What I wanted, was to transform this into a multidimensional array nested based on the values from the keys array, the output I was looking for is:
$bar = array(
[1] => array(
[a] => array(
[123] => array( //values array from above )
),
[b] => array(
[456] => array( //values array from above )
)
)
)
The keys can always be nested based on their position in the keys array, but the keys themselve are not always the same, keys handles a user defined grouping, so the order and values can change. I also didn't want duplicate keys.
array_merge failed me because in a lot of cases, the array keys are actually numeric ids. So, this function works - but I'm wondering if I made myself a new pair of gloves.
protected function convertAssociativeToMulti( &$output, $keys, $value )
{
$temp = array();
$v = array_values( $keys );
$s = sizeof( $v );
for( $x = 0; $x < $s; $x++ )
{
$k = $v[ $x ];
if ( $x == 0 )
{
if ( !array_key_exists( $k, $output ) )
$output[ $k ] = array();
$temp =& $output[ $k ];
}
if ( $x && ( $x + 1 ) !== $s )
{
if( !array_key_exists( $k, $temp ) )
$temp[ $k ] = array();
$temp =& $temp[$k];
}
if ( ( $x + 1 ) == $s )
$temp[$k] = $value;
}
}
$baz = array();
foreach( $foo as $bar )
{
$this->convertAssociativeToMulti( $baz, $bar['keys'], $bar['values'] );
}
So, how do you do this more simply / refactor what I have?
This is a bit more concise (See it in action here):
$bar=array();
foreach($foo as $item)
{
$out=&$bar;
foreach($item['keys'] as $key)
{
if(!isset($out[$key])) $out[$key]=array();
$out=&$out[$key];
}
foreach($item['values'] as $k=>$v) $out[$k]=$v;
// $out=array_merge($out,$item['values']); -- edit - fixed array_merge
}
var_dump($bar);
I know there's a ton of answers but I can't seem to get it right. I have the following arrays and what I've tried:
$a = array ( 0 => '1421' , 1 => '2241' );
$b = array ( 0 => 'teststring1' , 1 => 'teststring2' );
$c = array ( 0 => 'teststring3' , 1 => 'teststring4' );
$d = array ( 0 => 'teststring5' , 1 => 'teststring6' );
$e = array_combine($a, array($b,$c,$d) );
But with this I get the error array_combine() [function.array-combine]: Both parameters should have an equal number of elements.
I know it's because the $a's array values aren't keys. That's why I'm coming here to see if I could get some help with an answer that can help me make it look something like this:
array(2) {
[1421]=>array( [0] => teststring1
[1] => teststring3
[2] => teststring5
)
[2241]=>array( [0] => teststring2
[1] => teststring4
[2] => teststring6
)
}
If you have control over creating the arrays, you should create them like:
$a = array ('1421' ,'2241');
$b = array ('teststring1', 'teststring3', 'teststring5');
$c = array ('teststring2', 'teststring4', 'teststring6');
$e = array_combine($a, array($b,$c) );
If not, you have to loop over them:
$result = array();
$values = array($b, $c, $d);
foreach($a as $index => $key) {
$t = array();
foreach($values as $value) {
$t[] = $value[$index];
}
$result[$key] = $t;
}
DEMO
Here is a one-liner in a functional coding style. Calling array_map() with a null function parameter followed by the "values" arrays will generate the desired subarray structures. array_combine() does the key=>value associations.
Code (Demo)
var_export(array_combine($a, array_map(null, $b, $c, $d)));
Output:
array (
1421 =>
array (
0 => 'teststring1',
1 => 'teststring3',
2 => 'teststring5',
),
2241 =>
array (
0 => 'teststring2',
1 => 'teststring4',
2 => 'teststring6',
),
)
Super clean, right? I know. It's a useful little trick when you don't have control of the initial array generation step.
Here's a new version of array_merge_recursive which will handle integer keys. Let know how it goes.
$a = array ( 0 => '1421' , 1 => '2241' );
$b = array ( 0 => 'teststring1' , 1 => 'teststring2' );
$c = array ( 0 => 'teststring3' , 1 => 'teststring4' );
$d = array ( 0 => 'teststring5' , 1 => 'teststring6' );
$e = array_combine($a, array_merge_recursive2($b, $c, $d));
echo "<pre>";
print_r($e);
function array_merge_recursive2() {
$args = func_get_args();
$ret = array();
foreach ($args as $arr) {
if(is_array($arr)) {
foreach ($arr as $key => $val) {
$ret[$key][] = $val;
}
}
}
return $ret;
}