Я хотел бы преобразовать этот двухмерный массив записей:
[records] => Array ( [0] => Array ( [0] => Pears [1] => Green [2] => Box [3] => 20 ) [1] => Array ( [0] => Pears [1] => Yellow [2] => Packet [3] => 4 ) [2] => Array ( [0] => Peaches [1] => Orange [2] => Packet [3] => 4 ) [3] => Array ( [0] => Apples [1] => Red [2] => Box [3] => 20 ) )
В этот трехмерный массив, где каждый ключ массива сгруппирован по определенному значению из исходного массива:
[converted_records] => Array ( [Pears] => Array ( [0] => Array ( [0] => Green [1] => Box [2] => 20 ) [1] => Array ( [0] => Yellow [1] => Packet [2] => 4 ) ) [Peaches] => Array ( [0] => Array ( [0] => Orange [1] => Packet [2] => 4 ) ) [Apples] => Array ( [0] => Array ( [0] => Red [1] => Box [2] => 20 ) ) )
Я могу сделать это так:
$array = // Sample data like the first array above $storage = array(); $cnt = 0; foreach ($array as $key=>$values) { $storage[$values[0]][$cnt] = array ( 0 => $values[1], 1 => $values[2], 2 => $values[3] ); $cnt ++; }
Я хотел знать, есть ли более оптимальный способ сделать это. Я не знаю о каких-либо функциях в PHP, которые могут это сделать, поэтому я могу только предположить, что это в основном, как это будет сделано.
Проблема в том, что это повторяется так много раз, и каждая маленькая миллисекунда будет рассчитывать, поэтому я действительно хочу знать, что является лучшим способом выполнить эту задачу?
РЕДАКТИРОВАТЬ
Массив записей создается путем разбора файла .CSV следующим образом:
$records = array_map('str_getcsv', file('file.csv'));
EDIT # 2
Я выполнил простой тестовый тест по набору из 10 результатов (по 5 тыс. Записей), чтобы получить среднее время выполнения 0,645478 секунд. Конечно, перед этим есть еще несколько вещей, поэтому это не является истинным показателем фактической производительности, а хорошим показателем для сравнения с другими методами.
EDIT # 3
Я сделал тест с около 20 раз записями. Средняя моя рутина была 14.91971.
В какой-то момент ответ @ num8er ответил на $records[$key][] = array_shift($data);
перед обновлением ответа, как сейчас.
Когда я попробовал тестирование с большим набором результатов, у него закончилось нехватка памяти, так как она породила ошибку для каждой записи.
При этом, как только я сделал $records[$key][] = $data;
процедура завершилась со средним значением 18.03699 секунд с помощью gc_collect_cycles()
.
Я пришел к выводу, что хотя метод @ num8ers быстрее для небольших файлов, для более крупных методов мой метод работает быстрее.
чтение большого файла в память с помощью файла () (1-я итерация при чтении файла)
а затем итерации строк с помощью array_map (вторая итерация после каждой строки файла считывается в массив)
делать foreach по массиву (3-я итерация)
это плохая идея, когда вы ищете производительность.
Вы повторяете 3 раза. так что о 100K записей? он будет итерации 300K раз?
наиболее эффективный способ – это делать это во время чтения файла. существует только 1 строка с итерацией – чтение (100K записей == 100K итерация):
ini_set('memory_limit', '1024M'); set_time_limit(0); $file = 'file.csv'; $file = fopen($file, 'r'); $records = array(); while($data = fgetcsv($file)) { $key = $data[0]; if(!isset($records[$key])) { $records[$key] = array(); } $records[$key][] = array(0 => $data[1], 1 => $data[2], 2 => $data[3]); gc_collect_cycles(); } fclose($file);
и здесь родительский -> обработка детей для огромных файлов:
<?php ini_set('memory_limit', '1024M'); set_time_limit(0); function child_main($file) { $my_pid = getmypid(); print "Starting child pid: $my_pid\n"; /** * OUR ROUTINE */ $file = fopen($file, 'r'); $records = array(); while($data = fgetcsv($file)) { $key = $data[0]; if(!isset($records[$key])) { $records[$key] = array(); } $records[$key][] = array(0 => $data[1], 1 => $data[2], 2 => $data[3]); gc_collect_cycles(); } fclose($file); unlink($file); return 1; } $file = __DIR__."/file.csv"; $files = glob(__DIR__.'/part_*'); if(sizeof($files)==0) { exec('split -l 1000 '.$file.' part_'); $files = glob(__DIR__.'/part_*'); } $children = array(); foreach($files AS $file) { if(($pid = pcntl_fork()) == 0) { exit(child_main($file)); } else { $children[] = $pid; } } foreach($children as $pid) { $pid = pcntl_wait($status); if(pcntl_wifexited($status)) { $code = pcntl_wexitstatus($status); print "pid $pid returned exit code: $code\n"; } else { print "$pid was unnaturally terminated\n"; } } ?>
Если вы ищете только чистый код:
$array = array_map('str_getcsv', file('file.csv')); $storage = array(); foreach ($array as $values) { $key = array_shift($values); $storage[$key][] = $values; }
Если у вас нет сотен тысяч записей в массиве, скорость тоже не должна беспокоить.