Php rearrange array according to the key - php

I tried convert the array type from $data to $data2 but didn't have success.
In the $data array all values placed according to dates.
But in the $data2 values are placed according to the title.
I wonder if it's convertable array.
$data['Group1']['Date1']['Empty'] = 5;
$data['Group1']['Date1']['Reservated'] = 1;
$data['Group1']['Date1']['WillReturn'] = 3;
$data['Group1']['Date1']['Remains'] = 1;
$data['Group1']['Date2']['Empty'] = 2;
$data['Group1']['Date2']['Reservated'] = 2;
$data['Group1']['Date2']['WillReturn'] = 3;
$data['Group1']['Date2']['Remains'] = -3;
$data['Group2']['Date1']['Empty'] = 0;
$data['Group2']['Date1']['Reservated'] = 1;
$data['Group2']['Date1']['WillReturn'] = 3;
$data['Group2']['Date1']['Remains'] = -4;
$data['Group2']['Date2']['Empty'] = 10;
$data['Group2']['Date2']['Reservated'] = 1;
$data['Group2']['Date2']['WillReturn'] = 1;
$data['Group2']['Date2']['Remains'] = 8;
$data2 = [
'Group1' => [
[ 'Title' => 'Empty',
'Date1' => 5,
'Date2' => 2,
],
[ 'Title' => 'Reservated',
'Date1' => 1,
'Date2' => 2,
],
[ 'Title' => 'WillReturn',
'Date1' => 3,
'Date2' => 3,
],
[ 'Title' => 'Remains',
'Date1' => 1,
'Date2' => -3,
],
// etc...
],
'Group2' => [
[ 'Title' => 'Empty',
'Date1' => 0,
'Date2' => 10,
],
[ 'Title' => 'Reservated',
'Date1' => 1,
'Date2' => 1,
],
[ 'Title' => 'WillReturn',
'Date1' => 3,
'Date2' => 1,
],
[ 'Title' => 'Remains',
'Date1' => -4,
'Date2' => -8,
],
// etc...
],
// etc...
];
Some try here:
$new = [];
$grp = array_keys($datax);
$i =0;
foreach($datax as $key => $val)
{
$dates = array_keys($val);
foreach($val as $k=>$v)
{
$cases = array_keys($v);
$caseAndVals[$i]=$v;
$i++;
}
}
$z =0;
$y = 0;
foreach($grp as $g)
{
foreach($cases as $c)
{
$new[$g][$z]['Title']=$c;
foreach($dates as $d)
{
$new[$g][$z][$d] = 'values which correspond to the date and title';
}
$z++;
}
}
I converted array according to group and cases but i didn't have success to place values corresponded dates...

You're very close.
To get the values which correspond to the date and title, use $data[$g][$d][$c].
And you need to reset $z to 0 each time through the $grp loop, so you get correct indexes on each group array.
$new = array();
$grp = array_keys($data);
foreach($data as $key => $val)
{
$dates = array_keys($val);
foreach($val as $k=>$v)
{
$cases = array_keys($v);
$caseAndVals[]=$v;
}
}
foreach($grp as $g)
{
$z = 0;
foreach($cases as $c)
{
$new[$g][$z]['Title']=$c;
foreach($dates as $d)
{
$new[$g][$z][$d] = $data[$g][$d][$c];
}
$z++;
}
}

Related

Loop through arrays with limitations

I have an array of transports:
$transports = [
0 => ['label' => 'Transport 1', 'maxPalettesToLoad' => 5],
1 => ['label' => 'Transport 2', 'maxPalettesToLoad' => 2]
];
and an array of palettes with certain products i want to "load" on the transport above
$palettes = [
0 => ['id_product' => 2, 'id_sale_order_item' => 1, 'amount' => 4],
1 => ['id_product' => 4, 'id_sale_order_item' => 4, 'amount' => 3]
];
What I'm struggling to accomplish is to load all the palettes onto transports where total number of loaded palettes is equal to maxPalettesToLoad parameter of each transport. I'm looking for a solution that will generate me values like:
$toret = [
'Transport 1' => [
0 => ['id_product' => 2, 'id_sale_order_item' => 1],
1 => ['id_product' => 2, 'id_sale_order_item' => 1],
2 => ['id_product' => 2, 'id_sale_order_item' => 1],
3 => ['id_product' => 2, 'id_sale_order_item' => 1],
4 => ['id_product' => 4, 'id_sale_order_item' => 4]
],
'Transport 2' => [
0 => ['id_product' => 4, 'id_sale_order_item' => 4],
1 => ['id_product' => 4, 'id_sale_order_item' => 4]
],
];
EDIT: Here is my attempt. It's kinda different in terms of data structure, because I simplified it to make it shorted
foreach ($transportsData as $transportData) {
$modelTransportOrder = new TransportOrder();
$modelTransportOrder->max_palettes_amount = $maxPalettesAmount;
$status &= $modelTransportOrder->save();
$amountAssigned = $transportData['palletes'];
if ($status) {
$j = 1;
foreach ($palettesData as $paletteData) {
if ($modelSaleOrderItem = SaleOrderItem::findOne([$paletteData['id_sale_order_item']])) {
for ($i = 0; $i < $paletteData['amount']; $i++) {
if ($j <= $amountAssigned) {
$modelTransportOrderItem = new TransportOrderItem();
$modelTransportOrderItem->id_transport_order = $modelTransportOrder->id;
$modelTransportOrderItem->id_product = $modelSaleOrderItem->id_product;
$modelTransportOrderItem->id_sale_order_item = $modelSaleOrderItem->id;
$modelTransportOrderItem->index = $j;
$status &= $modelTransportOrderItem->save();
// Index reset
if ($j == $amountAssigned) {
$j = 0;
break;
}
}
$j++;
}
} else {
$status = false;
}
}
} else {
// Zapis transportu nie powiódł się
}
}
I have managed to solve my problem using unset after each used palette:
foreach ($initedPalettes as $key => $palette) {
if ($i <= $amountAssigned) {
$modelsTransportOrderItem = self::createTransportOrderItem
(
$modelTransportOrder->id,
$palette['idProduct'],
$palette['idSaleOrderItem'],
$i
);
$status &= $modelsTransportOrderItem->save();
unset($initedPalettes[$key]);
$i++;
}
}

Random weighted distribution

For example I have an array like:
$items = [
'0' => [
'name' => 'item1',
'percent' => 10
],
'2' => [
'name' => 'item2',
'percent' => 20
],
'3' => [
'name' => 'item3',
'percent' => 30
],
'4' => [
'name' => 'item4',
'percent' => 40
],
];
And function:
function echoRandomItem(){
}
If I call this function it should return 'name' of the item depending on the 'percent' value. Basically if I call this function 100 times it should return item1 10 times, item2 20 times, item3 30 times, item4 40 times.
Here is a solution I've come up with thanks to Oliver's hint. $items is a given array. wrand() function is responsible for random weighted distribution calculation.
$items = [
'1' => [
'name' => 'item1',
'rand' => 10
],
'2' => [
'name' => 'item2',
'rand' => 20
],
'3' => [
'name' => 'item3',
'rand' => 30
],
'4' => [
'name' => 'item4',
'rand' => 40
],
];
function wrand($data) {
foreach ($data as $value) {
$itemsRand[] = $value ['rand'];
}
$totalw = array_sum($itemsRand);
$rand = rand(1, $totalw);
$curw = 0;
foreach ($data as $val) {
$curw += $val['rand'];
if ($curw >= $rand) return $val['name'];
}
return end($data);
}
Further code simply calls wrand() function 100 times and counts the results.
static $item1 = 0;
static $item2 = 0;
static $item3 = 0;
static $item4 = 0;
for ($i = 0; $i < 100; $i++){
$k = wrand($items);
if ($k == 'item1') {
$item1++;
} elseif ($k == 'item2'){
$item2++;
} elseif ($k == 'item3'){
$item3++;
} elseif ($k == 'item4'){
$item4++;
}
}
echo "item1 = $item1<br>";
echo "item2 = $item2<br>";
echo "item3 = $item3<br>";
echo "item4 = $item4";

Better way of looking for matching value to output result?

I have a few names I need to check for depending on the number associated with them. Right now I can accomplish this task with the following.
$detectInspector = array();
$detectInspector[558]="Name";
$detectInspector[559]="OtherName";
$detectInspector[560]="Someone";
echo $detectInspector[558];
The issue is I have hundreds of these I would have to type out. Is there an easier method to perhaps do something like
476 through 490 = name
518 through 530 = name
558 through 569 = othername
598 though 609 = othername
650 through 655 = someoneelse
690 through 695 = someoneelse
To explain how the code works:
Pull number from db
Check number against list to see who name
matches
echo result
You could try something like this :
First store your names within a multidimensional array with a name entry and an array with the ranges of the name. Obviously, the name is going to be set if the number is between the min and max value of each range.
$ranges = [
[
'name' => 'Jhon',
'ranges' => [
[1,50],
[120,200],
[401,409]
]
],
[
'name' => 'Jack',
'ranges' => [
[20,25],
[210,230],
],
],
[
'name' => 'Bill',
'ranges' => [
[245,270],
[301,350],
],
],
[
'name' => 'Steve',
'ranges' => [
[271,275],
],
],
];
$names = [];
foreach ($ranges as $nameProps) {
foreach ($nameProps['ranges'] as $range) {
list($min, $max) = $range;
$names[] = [
'name' => $nameProps['name'],
'min' => $min,
'max' => $max,
];
}
}
Then, assuming you get the $nb variable from the db :
$nb = 999;
$detectInspector = [];
for ($i = 1; $i <= $nb; $i++) {
$name = '';
foreach ($names as $k => $nameProps) {
if ($i >= $nameProps['min'] && $i <= $nameProps['max']) {
$name .= ($name ? ' | ' : '') . $nameProps['name'];
}
}
if ($name != '') {
$detectInspector[$i] = $name;
}
}
You can now use your $detectInspector value
var_dump($detectInspector);

PHP - How to create such array?

The question is simple, I want to create the array below dynamically, but the code I got now only outputs the last row. Is there anybody who knows what is wrong with my dynamically array creation?
$workingArray = [];
$workingArray =
[
0 =>
[
'id' => 1,
'name' => 'Name1',
],
1 =>
[
'id' => 2,
'name' => 'Name2',
]
];
echo json_encode($workingArray);
/* My not working array */
$i = 0;
$code = $_POST['code'];
$dynamicArray = [];
foreach ($Optionsclass->get_options() as $key => $value)
{
if ($value['id'] == $code)
{
$dynamicArray =
[
$i =>
[
'id' => $key,
'name' => $value['options']
]
];
$i++;
}
}
echo json_encode($dynamicArray);
You dont need to have the $i stuff that is adding another level to your array that you dont want.
$code = $_POST['code'];
$dynamicArray = [];
foreach ($Optionsclass->get_options() as $key => $value)
{
if ($value['id'] == $code)
{
$dynamicArray[] = ['id' => $key, 'name' => $value['options'];
}
}
echo json_encode($dynamicArray);
You are creating a new dynamic array at each iteration:
$dynamicArray =
[
$i =>
[
'id' => $key,
'name' => $value['options']
]
];
Instead, declare $dynamicArray = []; above the foreach, and then use:
array_push($dynamicArray, [ 'id' => $key, 'name' => $value['options']);
inside the array.

PHP - search in array and create new one

I want to avoid if it is possible foreach combined with if. I want to search the array, take out the matches and create new one base on result.
In this example I want to create separate arrays for each os -
$os1 = $array;
$os2 = $array...
Array looks like this:
$array = [
0 => [
'id' => 1,
'name' => 'name',
'os' => 1
],
1 => [
'id' => 2,
'name' => 'name',
'os' => 1
],
2 => [
'id' => 3,
'name' => 'name',
'os' => 2
],
3 => [
'id' => 3,
'name' => 'name',
'os' => 2
]
];
Use array_filter to reduce the input array to the expected result
$os = 1;
$data = array_filter($array, function($item) use ($os) {
return $item['os'] == $os;
});
The short one
$os1 = [];
$os2 = [];
$os3 = [];
foreach ($array as $item) {
${'os' . $item['os']}[] = array('id' => $item['id'], 'name' => $item[$name];
}
The better one
$os1 = [];
$os2 = [];
$os3 = [];
foreach ($array as $item) {
switch($item['os']) {
case 1:
$os1[] = array('id' => $item['id'], 'name' => $item[$name]);
break;
case 2:
$os2[] = array('id' => $item['id'], 'name' => $item[$name]);
break;
case 3:
$os3[] = array('id' => $item['id'], 'name' => $item[$name]);
break;
default:
throw new Exception('Unknown Os');
}
}
Also you maybe want to assign array($item['id'] => $item[$name]); instead of array('id' => $item['id'], 'name' => $item[$name]);
$os1 = [];
$os2 = [];
$os3 = [];
foreach ($array as $item) {
${'os' . $item['os']}[] = array($item['id'] => $item[$name]);
}

Categories