2013-12-21 3 views
3
Array 
(
    [0] => Array 
     (
      [color] => Brown 
     ) 

    [1] => Array 
     (
      [color] => Green 
     ) 

    [2] => Array 
     (
      [width] => 34 
     ) 

) 

мне нужно сделать это как этотслияния массив массивов без потери значений

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

[width] => Array 
    (
     [0] => 34 
    ) 

)

я пытаюсь со всеми инструментами массива. Но я не могу сделать это так, как будто я этого хочу.

+0

На основании каких условий? –

ответ

4

Так ты хотите merge массивы рекурсивно ... если существует только such an array_merge_recursive функция ... Почему бы вам не попробовать это:

$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); 

Это работало довольно чертовски хорошо для меня, as you can see for yourself here, too

Правда, в данном примере width воны «т быть массивом, так что вы получите:

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

Если вы нужду все, чтобы быть массив, то грязный исправить было бы использовать бросок:

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

переназначение $result дорожит второй раз, только литье их как массив гарантирует, что все значения будут, по-видимому, быть массивами. Массив, который преобразуется в массив, останется неизменным, так же как (int) 1 по-прежнему оценивает значение 1. Первоначальное значение (строки, целые числа, удваивает, ...) будет завернуто int массив, но объект будет преобразован в массив, поэтому будьте осторожны. Если объекты могут иметь место в этом массиве:

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

, вероятно, более безопасная ставка. Тем не менее, я выбрал не, чтобы пойти на этот подход, поскольку я все еще нахожу его довольно утомительным и глупым, чтобы обернуть все в массив, содержащий только одно значение ...

Для тех из вас, со странным предпочтением неосновательного кода, следующие один-лайнер конденсированный, но обратите внимание, свободный & рабочего примера ту же коду:

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

Это как ответ на Стюарт Уэйкфилд, который предложил один лайнер, используя call_user_func_array, что я всегда буду противостоять, пока я живу и дышу, BTW ...

+0

Вы можете просто сделать это как один liner '$ result = call_user_func_array ('array_merge_recursive', $ arr);' –

+0

@StuartWakefield: это уменьшит ремонтопригодность и добавит служебные данные в виде второго вызова функции. Цикл быстрее и легче читать ... кроме 'foreach ($ arr as $ a) $ result = array_merge_recursive (isset ($ result)? $ Result: array(), $ a);' является однострочным , тоже :) –

+0

Я полностью не согласен с тем, что он уменьшает ремонтопригодность, меньше кода = меньше для обслуживания и на самом деле происходит сокращение вызовов функций. 2 вызова, один для call_user_func_array и один для array_merge_recursive, тогда как решение цикла приводит к вызову count ($ a) x ... –

1

Я думаю, это должно сделать это, особенно если вы не знаете, какие ключи вы будете иметь:

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

Не нужно ли '$ merged_array [$ key2]' инициализировать массив? – Eric

+0

@ Эрик Так я действительно это сделал. Но позже я понял, что это действительно не нужно. (Посмотрите на мою историю изменений.) –

+0

Вот phpFiddle: http://phpfiddle.org/main/code/1m2-tbz –

7

Это довольно просто с array_column() (требуется PHP> = 5.5.0):

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

Живая скрипка: https://eval.in/81746


Если вы не знаете, ключи заранее, вот еще одно решение, использующее array_walk_recursive():

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

Живая скрипка: https://eval.in/81745

+0

Этот _does_ предполагает, что OP знает, с какими ключами он имеет дело, и что все они будут установлены в любой момент времени, что, если это неизвестно, или что, если вам придется поддерживать такой код, и постепенно добавляйте 'array_column' вызывает + клавиши по мере роста вашего проекта? –

+0

@EliasVanOotegem Мое первоначальное решение никогда не предназначалось для использования с высоким или переменным количеством ключей. Смотрите мое обновление, пожалуйста. – ComFreek

+0

Это должно работать, но я не понимаю, почему вы должны сделать это настолько сложным: 'array_walk_recursive' + экземпляр' Closure' + страшный '& $ result' (который можно укусить вас в спину) так много более многословный и вызывает намного больше накладных расходов, чем мой первоначальный, простой подход петли + встроенная функция массива –

0

просто использовать Еогеасп, как показано ниже - имяМассива = исходный массив -

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

Попробуйте использовать array_merge_recursive ИЛИ array_column

+0

Это скорее комментарий, чем ответ ...либо удалить или отредактировать –

0

На основе массива array_merge_recursive от Elias следующее введение небольшого исправления, слияние одного элемента в массив:

/* 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)); 

Производит:

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

     [width] => Array 
      (
       [0] => 34 
      ) 
    ) 

Вместо того, чтобы:

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

     [width] => 34 
    ) 

В качестве альтернативы, динамичный подход к решению array_column ComFreek в.

Это дает массив ключей:

/* 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))); 

как:

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

который может быть использован с этим фрагментом:

/* 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)); 

Чтобы создать желаемый результат:

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

     [width] => Array 
      (
       [0] => 34 
      ) 
    ) 

Примечание: функциональных вызовы могут быть полезными в большинстве языков над императивным стилем, хотя это потребует изменений ментально. Функциональные шаблоны открывают возможности оптимизации низкого уровня, которые в противном случае были бы невозможны. Например, карта массива может выполняться параллельно, тогда как цикл for не может, цикл for всегда будет иметь ограничение, которое он должен выполнять последовательно.

+0

Total overkill: экземпляр 'закрытия' +' call_user_func_array' полностью перевернут !, используйте простой цикл + 'array_merge_recursive' меньше кода, проще в обслуживании и быстрее (cf мой ответ) –

+1

Очень интересно, как существует много разных способов использования функций массива для создания одного и того же результата :) – ComFreek

+0

Кроме того: глядя на ваш бит 'array_map' +' array_keys' + 'call_user_func_array' и' array_merge', который присваивает '$ keys', я думаю, вы могли бы добавьте там вызов 'array_unique'. Серьезно: получение ключей приводит к 5 различным функциям (где один является экземпляром класса Lambda => класса Closure!), А 'array_merge' называется N раз, где N == count ($ array). Разве вы не думаете, что это немного. Опять же: сравните его с 'foreach' (= languange construct) + N вызывает' array_merge_recursive'. Что выглядит как более простой альтернативой вам? –

Смежные вопросы