Преобразование плоского массива в массив, сгруппированный по категориям

У меня есть таблица базы данных, которая выглядит так:

uid | group | category 1 | group1 | cat1 2 | group1 | cat2 3 | group2 | cat3 4 | group2 | cat4 5 | group2 | cat5 6 | group3 | cat6 7 | group3 | cat7 

Но мне нужны эти данные в массиве, который группирует категории по их group .

Например, мой массив должен выглядеть так:

 Array ( [group1] => Array ( [0] => Array ( [0] => 1 [1] => cat1 ) [1] => Array ( [0] => 2 [1] => cat2 ) ) [group2] => Array ( [0] => Array ( [0] => 3 [1] => cat3 ) [1] => Array ( [0] => 4 [1] => cat4 ) [2] => Array ( [0] => 5 [1] => cat5 ) ) [group3] => Array ( [0] => Array ( [0] => 6 [1] => cat6 ) [1] => Array ( [0] => 7 [1] => cat7 ) ) ) 

Я написал цикл foreach, который делает только это, но у меня есть проблема.

Моя проблема заключается в том, что она всегда не учитывает последнюю строку таблицы, и я не уверен, как ее исправить. На мой взгляд, логика диктует, что она всегда должна работать.

Я думал, что после цикла я могу просто добавить последнюю строку в новый массив, но я думаю, что это может вызвать проблемы, если последняя строка имеет другую группу, и я предпочел бы, чтобы решение было встроено в цикл foreach.

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

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

Моя петля:

 $pass = []; foreach($stmt as $key => $value) { if(empty($currentGroup)) $currentGroup = $value['group']; if(empty($temp)) $temp = []; if($currentGroup != $value['group'] || $key+1 == count($stmt)) { $pass[$currentGroup] = $temp; $currentGroup = $value['group']; $temp = []; $temp[] = [$stmt[$key]['uid'], $stmt[$key]['category']]; } else { $temp[] = [$stmt[$key]['uid'], $stmt[$key]['category']]; } } 

Solutions Collecting From Web of "Преобразование плоского массива в массив, сгруппированный по категориям"

Это должно сделать следующее:

 <?php //Create an array to store our grouped rows $grouped = array(); //Loop over all rows returned by the $stmt that has been executed. //You could probably remove the key from here, it's not needed it seems. //The keys within the $value array will match the names of the columns in //the database, foreach($stmt as $key => $value){ //As we're storing by the group value from the row we first want to //check if our grouped array contains a key for the group of the row //being processed. If it does not, create an empty array within the //grouped data for this group. if(!array_key_exists($value['group'], $grouped)){ $grouped[$value['group']] = array(); } //Knowing we will always have an array element for the rows group //we can blindly append the values for this row to the grouped //container using its values. //'[] =' is just short hand append. $grouped[$value['group']][] = array( $value['uid'], $value['category'] ); } 

Надеюсь, это поможет!


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

 <?php //Setting the whole row (minus the group) rather than just the uid //and category explicitly allows this code to work without modification //as the datatable changes, ie. new columns. Assuming that is the 'group' //column remains present unset($value['group']); $grouped[$value['group']][] = $value; с <?php //Setting the whole row (minus the group) rather than just the uid //and category explicitly allows this code to work without modification //as the datatable changes, ie. new columns. Assuming that is the 'group' //column remains present unset($value['group']); $grouped[$value['group']][] = $value; 

Теперь можно получить доступ к данным с объединенным содержимым, используя следующее:

 <?php //Acceess data via column name not array index, yay! echo $grouped['group1']['uid'] 

Я снова нуждался в этом, поэтому создал функцию, основанную на ответе @ JParkinson1991 .

Я помещаю это здесь для документации и, возможно, помогаю будущим читателям.

 function groupArray($arr, $group, $preserveSubArrays = false, $preserveGroupKey = false) { $temp = array(); foreach($arr as $key => $value) { $groupValue = $value[$group]; if(!$preserveGroupKey) { unset($arr[$key][$group]); } if(!array_key_exists($groupValue, $temp)) { $temp[$groupValue] = array(); } if(!$preserveSubArrays){ $data = count($arr[$key]) == 1? array_pop($arr[$key]) : $arr[$key]; } else { $data = $arr[$key]; } $temp[$groupValue][] = $data; } return $temp; } с function groupArray($arr, $group, $preserveSubArrays = false, $preserveGroupKey = false) { $temp = array(); foreach($arr as $key => $value) { $groupValue = $value[$group]; if(!$preserveGroupKey) { unset($arr[$key][$group]); } if(!array_key_exists($groupValue, $temp)) { $temp[$groupValue] = array(); } if(!$preserveSubArrays){ $data = count($arr[$key]) == 1? array_pop($arr[$key]) : $arr[$key]; } else { $data = $arr[$key]; } $temp[$groupValue][] = $data; } return $temp; } 

Сломать

 function groupArray($arr, $group, $preserveGroupKey = false, $preserveSubArrays = false) 

Эта функция принимает от 2 до 4 параметров.

  1. Плоский массив, который вы хотите сгруппировать (массив)
  2. Ключ, который вы хотите сгруппировать с помощью (string / int)
  3. Возможность сохранения группового ключа в выходе каждого вспомогательного массива (Boolean)
  4. Возможность сохранения вспомогательных массивов. Если в каждом вспомогательном массиве существует только 1 ключ, функция будет хранить только одно значение для каждой строки вместо массива (Boolean)

Первый параметр – это сам массив, второй параметр – это ключ, который вы хотите сгруппировать, а третий (необязательный) параметр – это логическое значение, которое сообщает функции, если вы хотите сохранить групповой ключ в вспомогательных массивах.


 $temp = array(); foreach($arr as $key => $value) { $groupValue = $value[$group]; if(!$preserveGroupKey) { unset($arr[$key][$group]); } if(!array_key_exists($groupValue, $temp)) { $temp[$groupValue] = array(); } $temp[$groupValue][] = $arr[$key]; } с $temp = array(); foreach($arr as $key => $value) { $groupValue = $value[$group]; if(!$preserveGroupKey) { unset($arr[$key][$group]); } if(!array_key_exists($groupValue, $temp)) { $temp[$groupValue] = array(); } $temp[$groupValue][] = $arr[$key]; } 

Во-первых, мы создаем временный массив с именем $temp

Затем мы перебираем массив, захватив ключ (который должен быть строкой или int), и значение (которое должно быть массивом).

Мы устанавливаем $groupValue независимо от того, какое значение имеет $groupValue вами $group , например, «группа» в приведенном ниже примере.

 $arr = [ 0 => [ "group" => "group1", "name" => "Bob", ], 1 => [ "group" => "group1", "name" => "Randy", ], 2 => [ "group" => "group1", "name" => "Susan", ], 3 => [ "group" => "group2", "name" => "Larry", ], 4 => [ "group" => "group2", "name" => "David", ], 5 => [ "group" => "group3", "name" => "Perry", ], ]; 

Затем мы проверяем, хотим ли мы $preserveGroupKey . Если это логическое значение ложно (и по умолчанию), ключ будет удален, оставив несколько подмассивов только с ключевым словом «имя».

Теперь мы проверяем, существует ли $groupValue в нашем массиве $temp , если это не так, мы создаем его.

Затем мы добавляем к $temp[$groupValue] любые значения текущей строки. Из приведенного выше примера мы получим:

 Array ( [group1] => Array ( [0] => Bob [1] => Randy [2] => Susan ) [group2] => Array ( [0] => Larry [1] => David ) [group3] => Array ( [0] => Perry ) ) 

Или, если третий параметр установлен в true, вы получите:

 Array ( [group1] => Array ( [0] => Array ( [name] => Bob ) [1] => Array ( [name] => Randy ) [2] => Array ( [name] => Susan ) ) [group2] => Array ( [0] => Array ( [name] => Larry ) [1] => Array ( [name] => David ) ) [group3] => Array ( [0] => Array ( [name] => Perry ) ) )