3
Array ( [0] => Array ( [color] => Brown ) [1] => Array ( [color] => Green ) [2] => Array ( [width] => 34 ) ) 

i need to make it like this

[color] => Array ( [0] => green [1] => brown ) [width] => Array ( [0] => 34 ) 

)

i am trying with all the array tools. But i cant make it like i want it.

2

6 Answers 6

7

This is fairly simple with array_column() (requires PHP >= 5.5.0):

$result = array[ 'color' => array_column($arr, 'color'), 'width' => array_column($arr, 'width') ]; 

Live fiddle: https://eval.in/81746


If you do not know the keys beforehand, here is another solution using array_walk_recursive():

$result = []; array_walk_recursive($arr, function($value, $key) use (&$result) { if (!isset($result[$key])) { $result[$key] = []; } $result[$key][] = $value; }); 

Live fiddle: https://eval.in/81745

Sign up to request clarification or add additional context in comments.

8 Comments

This does assume the OP knows what keys he's dealing with, and that they'll all be set at any given time, what if that's an unknown, or what if you'd have to maintain code like this, and find yourself gradually adding array_column calls + keys as your project grows?
@EliasVanOotegem My original solution was never intended to be used with a high or variable amount of keys. See my update, please.
That ought to work, but I can't see why you should make it so complicated: array_walk_recursive + instance of Closure + the dreaded &$result (that one can bite you in the back) is so much more verbose and causes so much more overhead than my initial, simple approach of loop + built-in array function
Your approach being more elegant is subjective. I happen to strongly dislike closures and lambda's in PHP, love them in scheme or JS, but not in PHP. Your benchmark did surprize me at first, but it's not a valid test, really: PHP doesn't have block scope, so it caches your instance of Closure, and you declare the assoc array when timing my approach. I've poured both our takes into functions, predeclare all used vars (except for the $time vars), and then, My approach was faster.
Don't mention it... I like benchmarking stuff, and I'm still surprized how little overhead a Closure instance generates in PHP 5.5. I might have to reconsider my preconceived notions on the matter, especially when using Symphony2 form-events. Glad to see you're not mistaken my enthousiasm and slight obsessiveness for being competitive or as me being a twat, that has to be right all the time. :-)
|
4

So you want to merge the arrays recursively... if only such an array_merge_recursive function existed... Why don't you try this:

$a = array( array('colour' => 'green'), array('colour' => 'blue'), array('width' => 123) ); $result = array(); foreach($a as $arr) { $result = array_merge_recursive($result, $arr); } var_dump($result); 

That worked pretty darn well for me, as you can see for yourself here, too

True, in the given example width won't be an array, so you get:

array('colour' => array('green','blue'),'width' => 123); 

If you need everything to be an array, then a dirty fix would be to use a cast:

foreach($result as $k => $v) $result[$k] = (array) $v; 

Reassigning the $result values a second time, only casting them as an array ensures that all values will, evidently, be arrays. An array that is cast to an array will remain unchanged, just like (int) 1 still evaluates to 1. A primitive value (strings, integers, doubles,...) will be wrapped int an array, but an object will be transformed into an array, so be careful. If objects are likely to occur in this array:

foreach($result as $k => $v) $result[$k] = is_array($v) ? $v : array($v); 

is probably the safer bet. However, I chose not to go for this approach as I still find it pretty tedious and silly to wrap everything up into an array, containing only 1 value...

For those of you with a strange preference for unmaintainable code, the following one-liner is a condensed, but notice free & working example of the same code:

foreach($a as $arr) $result = array_merge_recursive(isset($result) ? $result : array(), $arr); 

This is as a response to Stuart Wakefield who suggested a one-liner using call_user_func_array, which is something I'll always oppose, for as long as I live and breathe, BTW...

12 Comments

You could simply do this as a one liner $result = call_user_func_array('array_merge_recursive', $arr);
@StuartWakefield: that would reduce maintainability and add overhead in the form of a second function call. A loop is faster, and easier to read... besides foreach($arr as $a) $result = array_merge_recursive(isset($result) ? $result : array(), $a); is a one-liner, too :)
I totally disagree that it reduces maintainability, less code = less to maintain and actually there is a reduction of function calls. 2 calls, one to call_user_func_array and one to array_merge_recursive, whereas the loop solution results in count($a) x function calls...
@StuartWakefield "Less code, less to maintain" does not always hold true. Besides that, I would really add a comment in the code explaining your one-liner.
@StuartWakefield: Interesting... switching down to 5.4 significantly reduces the performance of call_user_func_array, though... I guess there have been a lot of engine improvements concerning Closure's and the like +, of course call_user_func_array adds function call, but reduces number of assignments, I guess that's where the performance benefit is coming from. Still, not my preferred coding style, but you're right, it turns out to be faster.
|
1

I guess this should do it, especially if you don't know what keys you will have:

foreach ($original_array as $val1) foreach ($val1 as $key2=>$val2) $merged_array[$key2][] = $val2; 

17 Comments

Doesn't $merged_array[$key2] need to be initialized to an array?
@Eric That's the way I had it first indeed. But later I realized it isn't really needed. (Look at my edit history.)
Is that a documented feature of the [] syntax?
@Eric: somewhere, it'll be mentioned in the documents, but essentially it's syntactic sugar for array_push($arr, $val)
@Eric: beats me. I threw it in phpFiddle and it worked without any notice, warning or error.
|
0

just use foreach like below -- arrayName = your original array --

foreach($arrayName as $newArr){ if($newArr['color']){ $tempArr['color'][] = $newArr['color']; } if($newArr['width']){ $tempArr['width'][] = $newArr['width']; } } 

Comments

0

Building upon Elias's array_merge_recursive answer, the following introduces a small fix to turn single item merge into an array:

/* This version uses the function array_merge_recursive to collect * all of the values for the nested arrays by key * * @see http://willem.stuursma.name/2011/09/08/parallel-array_map-with-hiphop/ * @see http://willem.stuursma.name/2010/11/22/a-detailed-look-into-array_map-and-foreach/ * for why for loops are better than array_map in general */ $result = array_map(function($item) { /* The array_merge_recursive function doesn't add * values to an array if there was only one found * if the item isn't an array, make it an array */ return is_array($item) ? $item : array($item); /* Calls the array_merge_recursive function applying all of * the nested arrays as parameters. * * @see http://php.net/array_merge_recursive * @see http://www.php.net/call_user_func_array */ }, call_user_func_array('array_merge_recursive', $arr)); 

Produces:

Array ( [color] => Array ( [0] => green [1] => brown ) [width] => Array ( [0] => 34 ) ) 

Instead of:

Array ( [color] => Array ( [0] => green [1] => brown ) [width] => 34 ) 

Alternatively, a dynamic approach to ComFreek's array_column solution.

This gives you the array of the keys:

/* Gets the keys of the nested arrays as a single array of keys by first * mapping the nested arrays to an array of keys they contain and then * by merging these arrays and killing duplicates * * @see http://php.net/function.array-unique * @see http://www.php.net/call_user_func_array * @see http://www.php.net/array_merge * @see http://www.php.net/array_map */ $keys = array_unique(call_user_func_array('array_merge', array_map(function($item) { /* Replaces the nested array of keys and values with an array * of keys only in the mapped array * * @see http://www.php.net/array_keys */ return array_keys($item); }, $arr))); 

As:

Array ( [0] => color [1] => width ) 

Which can be used with this snippet:

/* Combines the array of keys with the values from the nested * arrays. * * @see http://php.net/array_combine * @see http://www.php.net/manual/en/function.array-map.php */ $result = array_combine($keys, array_map(function($key) use($arr) { /* Collects the values from the nested arrays * * @see http://php.net/array_column */ return array_column($arr, $key); }, $keys)); 

To create the desired output:

Array ( [color] => Array ( [0] => green [1] => brown ) [width] => Array ( [0] => 34 ) ) 

Note: functional calls can be beneficial in most languages over an imperative style although it does require a shift mentally. Functional patterns open up the possibilities of low level optimizations that otherwise wouldn't be possible. Array map, for example, could be executed in parallel, whereas a for loop cannot, the for loop will always have a restriction that it must execute sequentially.

7 Comments

Total overkill: an instance of closure + call_user_func_array is completely over the top!, use a simple loop + array_merge_recursive is less code, easier to maintain and faster, too (cf my answer)
It's very interesting how many different ways of using array functions for producing the same result exist :)
In addition: looking at your array_map + array_keys + call_user_func_array & array_merge bit, which assigns $keys, I think you could add an array_unique call there. Seriously: getting the keys takes you 5 different functions (where one is a lambda => instance of Closure class!), and array_merge is called N times, where N == count($array). Don't you think that's a bit much. Again: compare it to foreach (= languange construct) + N calls to array_merge_recursive. Which looks like the cleaner alternateive to you?
For loops are so passé, real men use functions! Good shout with the array_unique. Single call to array_merge_recursive vs n calls... It supports multiple array arguments, why not use that.
I've added your array_unique suggestion. P.S small thing, with a single value array_merge_recursive does not put the values in an array as the OP showed.
|
-1

Try using array_merge_recursive OR array_column

1 Comment

This is more a comment than an answer... either delete or edit

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.