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

#php #html

#php #HTML

Вопрос:

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

 <form id="results" action="launchresults.php" method="post"></form>
<form id="partslist" action='' method='post'></form>

<input type="text" name="partlist" id="partlist" form="partslist" />
<input type="submit" name='additem' value="Add Item" form="partslist" />
<input type="submit" name="clear" value="clear" form="partslist" />

<?php if (isset($_POST['additem'])) {
   if(!array_key_exists("parts", $_SESSION)) {
      $_SESSION["parts"] = array();
   }
   if(array_key_exists("parts", $_SESSION) amp;amp; array_key_exists($_POST['partlist'],$_SESSION["parts"])) {
      $increasevalue = $_SESSION["parts"][$_POST['partlist']]['quantity'];
      $_SESSION["parts"][$_POST['partlist']]['quantity'] = $increasevalue 1;
   }
   else {   
      $_SESSION["parts"][$_POST['partlist']] = array("quantity" => 1);
   }
}

if(isset($_POST['clear'])) {
   $_SESSION = array();
}

if(array_key_exists("parts", $_SESSION)):
   foreach ($_SESSION["parts"] as $partlist => $partlist_quantity):
      foreach ($partlist_quantity as $key => $value): ?>
         <input type="text" name="items[]" value="<?php echo $partlist; ?>" />
         <input type="number" name="quantity" value="<?php echo $value; ?>" />
      <?php endforeach; ?>
   <?php endforeach; ?>
<?php endif; ?>

<input type="submit" name="submit" form="results" />
  

Я могу сканировать штрих-коды деталей для построения своих массивов. Если часть — это то, что я уже отсканировал, это увеличивает количество на 1. Поля ввода доступны для редактирования, но в настоящее время код не позволяет обновлять эти поля вручную. Когда я нажимаю Отправить, я получаю что-то вроде этого:

     Array
(
    [parts] => Array
        (
            [12345] => Array
                (
                    [quantity] => 6
                )

            [errrt] => Array
                (
                    [quantity] => 2
                )

            [ffggg] => Array
                (
                    [quantity] => 4
                )

            [wefewf] => Array
                (
                    [quantity] => 10
                )

        )

)
  

Что я пытаюсь выяснить сейчас, так это как найти ключевую часть, посмотреть на количество для этой части, а затем разделить все по этому значению на равные массивы. Итак, основной частью выше была ‘errrt’, тогда я бы хотел разделить все на 2 и в итоге получить что-то, что выглядит примерно так…

 Array
(
    [errrt1] => Array
        (
            [12345] => Array
                (
                    [quantity] => 3
                )

            [ffggg] => Array
                (
                    [quantity] => 2
                )

            [wefewf] => Array
                (
                    [quantity] => 5
                )

        )
    [errrt2] => Array
        (
            [12345] => Array
                (
                    [quantity] => 3
                )

            [ffggg] => Array
                (
                    [quantity] => 2
                )

            [wefewf] => Array
                (
                    [quantity] => 5
                )

        )
)
  

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

Комментарии:

1. Не могли бы вы использовать всего несколько вещей, если вы собираетесь публиковать образцы данных, var_export поскольку это создает массивы, которые можно использовать в коде.

Ответ №1:

Вот так:

 $a = array (
    'parts' => 
    array (
        12345 => 
        array (
            'quantity' => 6
        ),
        'errrt' => 
        array (
            'quantity' => 2
        ),
        'ffggg' => 
        array (
            'quantity' => 4
        ),
        'wefewf' => 
        array (
            'quantity' => 10
        )
    )
);

$choice = 'errrt';
//localize
$parts = $a['parts'];

//localize chosen 
$qty_chosen = isset($parts[$choice], $parts[$choice]['quantity']) ? $parts[$choice]['quantity'] : 0;

if(!$qty_chosen) die('Cannot divide by 0');

unset($parts[$choice]); //remove it
array_walk_recursive($parts, function(amp;$item)use($qty_chosen){
    $item = $item / $qty_chosen;
});

$result = [];
for($i=1;$i<=$qty_chosen;   $i){
    $result[$choice.$i] = $parts;
}


print_r($result);
  

Вывод

 Array
(
    [errrt1] => Array
        (
            [12345] => Array
                (
                    [quantity] => 3
                )

            [ffggg] => Array
                (
                    [quantity] => 2
                )

            [wefewf] => Array
                (
                    [quantity] => 5
                )

        )

    [errrt2] => Array
        (
            [12345] => Array
                (
                    [quantity] => 3
                )

            [ffggg] => Array
                (
                    [quantity] => 2
                )

            [wefewf] => Array
                (
                    [quantity] => 5
                )

        )

)
  

Песочница

В этом случае мы можем просто использовать array_walk_recursive для разделения вложенных величин, но если в массивах есть другие элементы, вы не сможете этого сделать.

Если у вас есть другие элементы, которые вы можете использовать (вместо array_walk_recursive ):

  $parts = array_map(function($item)use($qty_chosen){
    $item['quantity'] = $item['quantity'] / $qty_chosen;
    return $item;
 }, $parts);
  

Или

  array_walk($parts, function(amp;$item)use($qty_chosen){
    $item['quantity'] = $item['quantity'] / $qty_chosen;
 });
  

Разница в том, что array_walk это более «волшебный» из 2, поскольку на самом деле он не предназначен для обновления массива, где as array_map специально разработан для этого. Мы можем сделать это с помощью array_walk_* функции (ов), но мы должны передать $item по ссылке с помощью amp; (что является совершенно другим уроком).

Лично я предпочитаю array_map в этом случае, поскольку это немного более читабельно. Если вы хотите получить действительно особенное (или чувствуете себя особенно ленивым), вы можете разделить следующим образом:

  $item['quantity'] /= $qty_chosen;
  

Что-то вроде .= или = и т.д. Я никогда не использую это, я предполагаю, что я недостаточно разделяю, чтобы действительно подумать об этом … ?

В любом случае, надеюсь, это поможет.

Комментарии:

1. зачем вам это array_walk_recursive , когда доступ к индексу был бы здесь совершенно разумным, особенно когда вы заметили недостаток? ;o/

2. when an index access would be perfectly reasonable here — по сути, вам нужно сделать то же самое, что и переход по массиву перед циклом for. Потому что в цикле for вам понадобится еще один цикл (но вы будете повторять это без необходимости каждый раз). Для каждой итерации цикла for требуется весь массив, минус один элемент, разделенный на {n} или $parts в моем коде. Итак, вы видите, что бессмысленно изменять это в цикле for, а затем мы делаем это раньше, что аналогично тому, что делает array walk. Мы бы просто делали это вручную.

3. с доступом к индексу я имел в виду вместо рекурсивного, просто array_walk и $item['quantity'] = $item['quantity'] / $qty_chosen;

4. это было проще набирать _recursive . lol В этом случае array_map лучше.

Ответ №2:

 $array = ['parts' => [
  '12345' => ['quantity' => 6],
  'errrt' => ['quantity' => 2],
  'ffggg' => ['quantity' => 4],
  'wefewf' => ['quantity' => 10],
]];

// i don't know how you determine the main part, but that's your cup of tea ;o)
$mainpart = 'errrt';

// fetching quantity of the main part:
$divider = $array['parts'][$mainpart]['quantity'];

// create the sub part, since they are all identical, 
// we make a sample "pattern", called "divided"
// (you could change the original array instead, 
// but I chose to leave it unchanged)
$divided = [];
foreach($array['parts'] as $partname => $part) {
    // the main part is not part of the pattern
    if($partname == $mainpart) {
        continue;
    }
    // if the quantity of the part is not dividable by
    // main part quantity, abort or whatever
    if($part['quantity'] % $divider != 0) {
        // echo error message or throw Exception or whatever
        // optionally set some flag and break;
        throw new Exception('part '.$partname.' has quantity that cannot be divided by '.$divider);
    }

    // fix the quantity.
    $part['quantity'] = $part['quantity'] / $divider;
    // add the part to the pattern.
    $divided[$partname] = $part;
}

$result = [];
// expand the pattern 
for($i = 1; $i <= $divider; $i  ) {
    $result[$mainpart.$i] = $divided;
}


var_export($result);