Подтвердить что ты не робот

PHP. Рекурсивно установите каждый элемент элемента массива в значение дочернего элемента при задании имени ключа childs

Начну с отображения нерекурсивного примера

Нерекурсивный пример

$given_key_name = 'site_id';

$rows[] = array(
    'site_id' => '0',
    'language_id' => '1',
    'name' => 'sitename',
    'description' =>'site desc',
);

$results = array();
foreach($rows as $row){
    $key_value = $row[$given_key_name];
    unset($row[$given_key_name]);
    $results[$key_value] = $row;
}

//  OR This method is faster than the forloop

$results = array_combine(array_column($rows, $given_key_name),$rows);
foreach($results as &$row){
    unset($row[$given_key_name]); 
}

$results Равно

$results[0] = array( 
    'language_id' => '1',
    'name' => 'sitename',
    'description' =>'site desc',
);

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

Пример

$given_key_names = array('site_id', 'language_id');

В этом случае требуемый результат будет.

$results[0][1] = array( 'name' => 'sitename', 'description' =>'site desc', );

Объяснение

Значение первых ключей было использовано как первый ключ в массиве $results, а новый пустой массив создается как его значение. $results[0] = array();

Поскольку есть второй ключ, его значение устанавливается как ключ к вновь созданному массиву, а его значение также является новым пустым массивом. $results[0][1] = array();

Поскольку ключей больше нет, пустой массив заполняется оставшимися значениями

$results[0][1] = array( 'name' => 'sitename', 'description' =>'site desc', );

поэтому мне бы хотелось две функции nestByKeyNames и unNestByKeyName.

Функция NestByKeyNames

Христианский ответ решает это

function nestByKeyNames($arrayRows, $arrayKeyOrder){

    // Prepare resulting array
    $arrayResult = array();

    // Cycle the input array
    foreach($arrayRows as $someRow){
        // We will acomplish this using references
        $current = &$arrayResult;

        // get the current level
        foreach($arrayKeyOrder as $someKey){
            $someValue = $someRow[$someKey];
            if(isset($current[$someValue])){
                $current = &$current[$someValue];
            }else{
                $current[$someValue] = array();
                $current = &$current[$someValue];
            }
            unset($someRow[$someKey]);
        }
        $current = $someRow;
    }
    return $arrayResult;
}

Интересно, может ли array_combine(array_column($arrayRows, $key_name),$arrayRows); использоваться вместо первой итерации для повышения производительности?

Это результат результатов инструкции select mysql.

$rows = array(
    array(
        'pri_id_1' =>1,
        'pri_id_2' =>1,
        'pri_id_3' =>1,
        'col_1' =>'col_value_1111',
        'col_2' =>'col_value_1112',
        'col_3' =>'col_value_1113',
    ),
    array(
        'pri_id_1' =>1,
        'pri_id_2' =>2,
        'pri_id_3' =>1,
        'col_1' =>'col_value_1211',
        'col_2' =>'col_value_1212',
        'col_3' =>'col_value_1213',
    ),
    array(
        'pri_id_1' =>1,
        'pri_id_2' =>3,
        'pri_id_3' =>1,
        'col_1' =>'col_value_1311',
        'col_2' =>'col_value_1312',
        'col_3' =>'col_value_1313',
    )
);

$keyNames = array('pri_id_1','pri_id_2','pri_id_3');
$results = nestByKeyNames($rows, $keyNames);

Производится следующий вывод

Array
(
    [1] => Array
        (
            [1] => Array
                (
                    [1] => Array
                        (
                            [col_1] => col_value_1111
                            [col_2] => col_value_1112
                            [col_3] => col_value_1113
                        )

                )

            [2] => Array
                (
                    [1] => Array
                        (
                            [col_1] => col_value_1211
                            [col_2] => col_value_1212
                            [col_3] => col_value_1213
                        )

                )

            [3] => Array
                (
                    [1] => Array
                        (
                            [col_1] => col_value_1311
                            [col_2] => col_value_1312
                            [col_3] => col_value_1313
                        )

                )

        )

)

Функция UnNestByKeyNames

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

function unNestByKeyNames($arrayRows, $arrayKeyOrder){


}

$keyNames = array('pri_id_1','pri_id_2','pri_id_3');
$rows = unNestKeyNames($results, $keyNames);

Моя истинная цель - взять результаты из инструкции MYSQL SELECT и заполнить форму, используя одно и то же соглашение об именах, используя nestByKeyNames.

например.

<input name="rows[1][1][1][col_1]" value="col_value_1" />

а затем преобразовать запрос $_POST обратно в инструкцию MYSQL INSERT, сначала используя unNestByKeyNames.

Из этого я создам оператор INSERT.

function returnValues($rows, $column_names){

    //validation has been removed for clarity

    $implode_VALUES = array();

    foreach ($rows as $key => $row) {
        $implode_row_values = array();
        foreach ($column_names as $column_name) {
            $implode_row_values[$column_name] = $row[$column_name];
        }
        if($implode_row_values){
            $implode_VALUES[] = " ('" . implode("','", $implode_row_values) . "') ";
        }
    }
    return $implode_VALUES;
}

$implode_COLUMNS = array('pri_id_1','pri_id_2','pri_id_3','col_1','col_2','col_3');

$implode_VALUES = returnValues($rows, $implode_COLUMNS)

$sql = "INSERT INTO table_name (" . implode(',', $implode_COLUMNS) . ") VALUES " . implode(',', $implode_VALUES);

В конечном результате должен быть создан оператор sql, подобный

INSERT INTO table_name (pri_id_1,pri_id_2,pri_id_3,col_1,col_2,col_3) VALUES ('1','1','1','NEW_value_1111','NEW_value_1112','NEW_value_1113') , ('1','2','1','NEW_value_1211','NEW_value_1212','NEW_value_1213') , ('1','3','1','NEW_value_1311','NEW_value_1312','NEW_value_1313')

Что мне хотелось бы

  • Предложения по улучшению функции 'nestByKeyNames' (производительность/ошибки)
  • поможет создать код unNestByKeyNames
  • Предложения по улучшению моего подхода "$ rows to mysql INSERT"
  • примеры того, как я мог бы сделать любой из моих кодов более эффективным.
4b9b3361

Ответ 1

Это было сложнее, чем я сначала представлял, но я считаю, что у меня грязное решение.

Прежде всего, это данные, с которыми я работаю. dumpr - это настраиваемая функция, которая форматирует var_dump лучше.

$arrayKeyOrder = array(
    'site_id',
    'language_id'
);

$original = array(
    array(
        'site_id' => '0',
        'language_id' => '1',
        'name' => 'sitename',
        'description' =>'site desc',
    ),

    array(
        'site_id' => '0',
        'language_id' => '2',
        'name' => 'sitename',
        'description' =>'site desc',
    ),

    array(
        'site_id' => '1',
        'language_id' => '1',
        'name' => 'sitename',
        'description' =>'site desc',
    ),

    array(
        'site_id' => '2',
        'language_id' => '1',
        'name' => 'sitename',
        'description' =>'site desc',
    ),
);

$zipped = doZip($original, $arrayKeyOrder);
$unzipped = unZip($zipped, $arrayKeyOrder);

dumpr($original);
dumpr($zipped);
dumpr($unzipped);

Вот функции zip и unzip:

function doZip($arrayRows, $arrayKeyOrder){

    // Prepare resulting array
    $arrayResult = array();

    // Cycle the input array
    foreach($arrayRows as $someRow){
        // We will acomplish this using references
        $current = &$arrayResult;

        // get the current level
        foreach($arrayKeyOrder as $someKey){
            $someValue = $someRow[$someKey];
            if(isset($current[$someValue])){
                $current = &$current[$someValue];
            }else{
                $current[$someValue] = array();
                $current = &$current[$someValue];
            }
            unset($someRow[$someKey]);
        }

        $current = $someRow;
    }

    return $arrayResult;
}


function unZip($arrayRows, $arrayKeyOrder, $arrayValues = array(), $depth = 0){

    $arrayResults = array();

    if($depth < count($arrayKeyOrder)){
        foreach($arrayRows as $key => $value){
            $arrayValues[$depth] = $key;
            $arrayResults[] =  unZip($value, $arrayKeyOrder, $arrayValues, $depth + 1);
        }
    }else{
        $extra = array_combine($arrayKeyOrder, $arrayValues);
        $result = array_merge($extra, $arrayRows);
        return $result;
    }

    if($depth == 0){
        for($i = 1; $i < count($arrayKeyOrder); $i++){
            $arrayResults = call_user_func_array('array_merge', $arrayResults);
        }        
    }

    return $arrayResults;
}

И, наконец, вот вывод. сообщите мне, если это то, о чем вы просили, и если он работал нормально на более крупном наборе данных.

/vhost/virtual/sandbox/public/index.php:54
array(4) {
    [0] = array(4) {
        [site_id] = string(1) "0"
        [language_id] = string(1) "1"
        [name] = string(8) "sitename"
        [description] = string(9) "site desc"
    }
    [1] = array(4) {
        [site_id] = string(1) "0"
        [language_id] = string(1) "2"
        [name] = string(8) "sitename"
        [description] = string(9) "site desc"
    }
    [2] = array(4) {
        [site_id] = string(1) "1"
        [language_id] = string(1) "1"
        [name] = string(8) "sitename"
        [description] = string(9) "site desc"
    }
    [3] = array(4) {
        [site_id] = string(1) "2"
        [language_id] = string(1) "1"
        [name] = string(8) "sitename"
        [description] = string(9) "site desc"
    }
}

/vhost/virtual/sandbox/public/index.php:55
array(3) {
    [0] = array(2) {
        [1] = array(2) {
            [name] = string(8) "sitename"
            [description] = string(9) "site desc"
        }
        [2] = array(2) {
            [name] = string(8) "sitename"
            [description] = string(9) "site desc"
        }
    }
    [1] = array(1) {
        [1] = array(2) {
            [name] = string(8) "sitename"
            [description] = string(9) "site desc"
        }
    }
    [2] = array(1) {
        [1] = array(2) {
            [name] = string(8) "sitename"
            [description] = string(9) "site desc"
        }
    }
}

/vhost/virtual/sandbox/public/index.php:56
array(4) {
    [0] = array(4) {
        [site_id] = int(1) 0
        [language_id] = int(1) 1
        [name] = string(8) "sitename"
        [description] = string(9) "site desc"
    }
    [1] = array(4) {
        [site_id] = int(1) 0
        [language_id] = int(1) 2
        [name] = string(8) "sitename"
        [description] = string(9) "site desc"
    }
    [2] = array(4) {
        [site_id] = int(1) 1
        [language_id] = int(1) 1
        [name] = string(8) "sitename"
        [description] = string(9) "site desc"
    }
    [3] = array(4) {
        [site_id] = int(1) 2
        [language_id] = int(1) 1
        [name] = string(8) "sitename"
        [description] = string(9) "site desc"
    }
}

Ответ 2

Попробуйте следующее:

// initialize your array
$all_rows = array();

// loop through query results
while( $row = $qry->fetch_assoc() )
{
    // temporarily store these vars for easy use later
    $s_id = $row['site_id'];
    $l_id = $row['language_id'];

    // create an empty array based on site_id and language_id
    $all_rows[ $s_id ][ $l_id ] = array();

    // loop through all columns returned from query
    foreach ( $row as $key => $val )
    {
        // if it not one of the two primary keys, push it to the array
        if ( ! in_array($key, $all_primary_keys) )
        {
            $all_rows[ $s_id ][ $l_id ][ $key ] = $val;
        }
    }
}

Ответ 3

Есть ли причина, по которой ниже не будет работать?

$results = array();
while($row = $qry->fetch_assoc()){

    $results[$row['site_id']][$row['language_id']] = array(

        'name'  =>  $row['name'],
        'description' => $row['description']

    );

}

Ответ 4

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

Первый получает прибыль указателей для решения первого шага проблемы:

function nestByKeyNames($rows, $aKeys) {
    $tab=Array();
    foreach ($rows as &$v) {
            // calculate the pointer position
            $t=&$tab;
            foreach ($aKeys as $v1) {
                    $t=&$t[$v[$v1]];
                    unset($v[$v1]);
            }
            // save the value
            $t=$v;
    }
    return $tab;
}

Этот использует рекурсивный алгоритм и дает обратный выход

function unNestByKeyNames($arrayRows, $aKeys){
    $t=Array();
    if (!count($aKeys)) return Array($arrayRows);
    foreach ($arrayRows as $k=>&$v) {
            $res=unNestByKeyNames($v, array_slice($aKeys,1));
            foreach ($res as $k1=>$v1) $t[]=array_merge(Array($aKeys[0]=>$k), $v1);
    }
    return $t;
 }

У меня нет предложения относительно вашего подхода SQL INSERT до тех пор, пока вы будете заботиться о SQL-инъекции, которая, я полагаю, может послужить причиной вашего комментария, "проверка достоверности была удалена для ясности"

Ответ 5

Нет никакого реального метода для того, что вы хотите, если вы хотите использовать первичный ключ, вам нужно знать имя столбца первичного ключа, вам не нужны столбцы, на которые вы запрашиваете. лучший способ сделать это - использовать ключевое слово AS в MySQL Query

SELECT primary as ID, ... где primary - это имя столбца вашего первичного ключа, а теперь ID - ваш первичный ключ в результирующем наборе.

Затем вы можете просто выполнить стандартный

$sortedResults = array();
while($row = $queryResult->fetch_assoc()){
    $rowId = $row["ID"];
    $sortedResults[$rowId] = $row;
}

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