hello stackoverflow :),
I block on this problem for a few days I think that the solution is with a recursive function but I cannot create it.
my main problem is that the source data is random, I can not determine neither the order nor the amount of data.
I would like to combine several array to be able to prepare my request in db
for example I can receive a table
array: {
color_id: [3,4],
size_id: [11, 6, 7]
}
and I would like to convert it to
color_id[
3 => size_id[11, 6, 7],
4 => size_id[11, 6, 7],
],
to simplify nothing it is possible to have x array, example
array: {
color_id: [3,4],
size_id: [11, 6, 7],
x_id: [8, 9],
}
to
color_id[
3 => size_id[
11 => x_id[8, 9],
6 => x_id[8, 9],
7 => x_id[8, 9]
],
4 => size_id[
11 => x_id[8, 9],
6 => x_id[8, 9],
7 => x_id[8, 9]
],
],
I have to be able to cover all possibilities,
Thanks for your help
Related
I want to calculate and store the dense rank and gapped rank for all entries in an array using PHP.
I want to do this in PHP (not MySQL because I am dealing with dynamic combinations 100,000 to 900 combinations per week, that’s why I cannot use MySQL to make that many tables.
My code to find the dense ranks is working, but the gapped ranks are not correct.
PHP code
$members = [
['num' => 2, 'rank' => 0, 'dense_rank' => 0],
['num' => 2, 'rank' => 0, 'dense_rank' => 0],
['num' => 3, 'rank' => 0, 'dense_rank' => 0],
['num' => 3, 'rank' => 0, 'dense_rank' => 0],
['num' => 3, 'rank' => 0, 'dense_rank' => 0],
['num' => 3, 'rank' => 0, 'dense_rank' => 0],
['num' => 3, 'rank' => 0, 'dense_rank' => 0],
['num' => 5, 'rank' => 0, 'dense_rank' => 0],
['num' => 9, 'rank' => 0, 'dense_rank' => 0],
['num' => 9, 'rank' => 0, 'dense_rank' => 0],
['num' => 9, 'rank' => 0, 'dense_rank' => 0]
];
$rank=0;
$previous_rank=0;
$dense_rank=0;
$previous_dense_rank=0;
foreach($members as &$var){
//star of rank
if($var['num']==$previous_rank){
$var['rank']=$rank;
}else{
$var['rank']=++$rank;
$previous_rank=$var['num'];
}//end of rank
//star of rank_dense
if($var['num']===$previous_dense_rank){
$var['dense_rank']=$dense_rank;
++$dense_rank;
}else{
$var['dense_rank']=++$dense_rank;
$previous_dense_rank=$var['num'];
}
//end of rank_dense
echo $var['num'].' - '.$var['rank'].' - '.$var['dense_rank'].'<br>';
}
?>
My flawed output is:
num
rank
dynamic rank
2
1
1
2
1
1
3
2
3
3
2
3
3
2
4
3
2
5
3
2
6
5
3
8
9
4
9
9
4
9
9
4
10
Notice when the error happens and there is a higher number in the number column it corrects the error in that row. See that when the number goes from 3 to 5.
Given that your results are already sorted in an ascending fashion...
For dense ranking, you need to only increment your counter when a new score is encountered.
For gapped ranking, you need to unconditionally increment your counter and use the counter value for all members with the same score.
??= is the "null coalescing assignment" operator (a breed of "combined operator"). It only allows the right side operand to be executed/used if the left side operand is not declared or is null. This is a technique of performing conditional assignments without needing to write a classic if condition.
Code: (Demo)
$denseRank = 0;
$gappedRank = 0;
foreach ($members as &$row) {
$denseRanks[$row['num']] ??= ++$denseRank;
$row['dense_rank'] = $denseRanks[$row['num']];
++$gappedRank;
$gappedRanks[$row['num']] ??= $gappedRank;
$row['rank'] = $gappedRanks[$row['num']];
// for better presentation:
echo json_encode($row) . "\n";
}
Output:
{"num":2,"rank":1,"dense_rank":1}
{"num":2,"rank":1,"dense_rank":1}
{"num":3,"rank":3,"dense_rank":2}
{"num":3,"rank":3,"dense_rank":2}
{"num":3,"rank":3,"dense_rank":2}
{"num":3,"rank":3,"dense_rank":2}
{"num":3,"rank":3,"dense_rank":2}
{"num":5,"rank":8,"dense_rank":3}
{"num":9,"rank":9,"dense_rank":4}
{"num":9,"rank":9,"dense_rank":4}
{"num":9,"rank":9,"dense_rank":4}
For the record, if you are dealing with huge volumes of data, I would be using SQL instead of PHP for this task.
It seems like you want the dynamic rank to be sequential?
Your sample data appears to be sorted, if this remains true for your real data then you can remove the conditional and just increment the variable as you assign it:
//start of rank_dense
$var['dense_rank']=++$dense_rank;
//end of rank_dense
It sounds like you're saying you won't be implementing a database.
Databases like MySQL can easily handle the workload numbers you outlined and they can sort your data as well. You may want to reconsider.
Hello here is an array of all values possibilities that should be an instance of the int we have as rank. But I would like this array to be empty first and find those values without if statements, so with a smart mathematical relation.
Example: a player who has the rank 3 would have those rewards: First time: At pos 0: 10 keys; pos 1: 13 keys; pos 2: 13 keys; 8 lives and 2 keys at pos 0 if he already registered their first time rewards.
(In fact there would be if satement only if the player never registered their rewards).
So I've tried to do this with digital sequences that I learned to school but it does not seems working.
Thank you for your time... and your help !
P.S.: I'm quite new here, sorry for any mistake.
Here is the schema of all possibilities stored in this array:
$rewards = [
1 => [
"count" => [7, 7, 7],
"lives" => 8,
"count_back" => [2, 2]
],
2 => [
"count" => [7, 10, 10],
"lives" => 10,
"count_back" => [1]
],
3 => [
"count" => [10, 13, 13],
"lives" => 13,
"count_back" => [2]
],
4 => [
"count" => [10, 13, 13],
"lives" => 15,
"count_back" => [2]
],
5 => [
"count" => [14, 15, 15],
"lives" => 18,
"count_back" => [2]
],
6 => [
"count" => [16, 18, 18],
"lives" => 20,
"count_back" => [2, 2]
]
];
So the only input we have for this command is the player rank (int). Starting to it I would like to find without if statements, that will be too big or this complete array we have above that would take too much datas in memory for nothing (because the player doesn't have several ranks) ; the specific reward.
For example: I have the input 1. So the output should be ["count" => [7, 7, 7], "lives" => 8] if the player never used the command. If he already used it so the output should be only ["count" => [2, 2]]
I have a table with a json column cast as array. The Schema creation has the column defined like this:
$table->json('row_ids');
In my class:
protected $casts = [
'row_ids' => 'array',
];
I generate the data in this array / column by getting every row id from another table like this:
$id_array = DB::table($table->name)->pluck('api_id')->toArray();
TableChannelRow::create([
'table_api_id' => $table->api_id,
'channel_api_id' => $channel->api_id,
'row_ids' => $id_array,
]);
When I dd a collection record I can see the columns in the target table OK, with one of the columns containing an array as expected:
#attributes: array:4 [▼
"api_id" => 2
"table_api_id" => 1
"channel_api_id" => 6
"row_ids" => "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, ▶"
]
When I check in MySQLWorkbench the data looks like this:
In another controller I want to add or remove entries from the array in this column like this:
$table_channel_row = TableChannelRow::where('table_api_id', '=', $rowId)
->where('channel_api_id', '=', $channelId)
->first();
$row_ids = $table_channel_row->row_ids;
if ($is_checked == 'yes') {
// Add value to array if it does not already exist
if (!in_array($row_id, $row_ids)) {
array_push($row_ids, $row_id);
}
} else {
// Remove value from array
$row_id_array[] = $row_id;
$row_ids = array_diff($row_ids, $row_id_array);
}
$table_channel_row->update([
'row_ids' => $row_ids,
]);
Now the data in MySQLWorkbench looks like this:
Why does it get stored looking like a PHP array in the first instance, then later on update it gets stored as a json object?
Additionally the remove PHP code is working, yet the add is not, though it does not trigger an exception (you can see the first value is removed in the second image, but I cannot find it in the object in MySQL when I trigger the code to add it)
What did I miss? Thanks!
The reason why it's saving differently is because array_diff returns an associative array whereas your initial data is an indexed array. Take the following for example:
$ids = [1, 2, 3, 4, 5];
$ids2 = [1, 2, 3];
Then if you perform an array_diff($ids, $ids2), it would return the following:
[
3 => 4,
4 => 5
]
So if you want to save as the same format as your initial one, you have to retrieve the values of the array using array_values:
$row_ids = array_values(array_diff($row_ids, $row_id_array));
I am cracking my brain and can't find a good solution for my problem. I am trying to design a system that I can use for batch picking in our order system.
The point is that from a set of orders I want to pick 6 orders that are most equal to each other. In our warehouse most orders are them so we can safe a lot of time by picking some orders at the same time.
Assume I have the following array:
<?php
$data = [
156 => [
1,
2,
7,
9,
],
332 => [
3,
10,
6
],
456 => [
1,
],
765 => [
7,
2,
10,
],
234 => [
1,
9,
3,
6,
],
191 => [
7,
],
189 => [
7,
6,
3,
],
430 => [
10,
9,
1,
],
482 => [
1,
2,
7,
],
765 => [
1,
5,
9,
]
];
?>
The array key is the order id, and the values are the product ID's it contains. If I want to pick the top 3 orders which look at much like each other, where do I start?
Any help would be much appreciated!
1. Step
Sort productId inside order (ASC)
2. Step
In loop check difference (array_diff) in each order to each other.
Create array with defference. For example:
$diff = [
'156' => [ //order id
'234' => 4, // with order 234 has 4 differences
'332' => 7, // with order 332 has 7 differences
// and so on...
],
]
3. Step
Order $diff by ASC and receive order with less differences.
Improvement
Also you could add total size of products in order for compare with difference. For example, If you have an order with 100 products and 10 diffs - it's better than order with 10 products and 9 diffs.
Here is what i would do if I had the problem :
$topOrders = [];
foreach($data as $value):
foreach($value as $order):
if(isset($$order)):
$$order++;
else:
$$order = 1;
endif;
$topOrders[$order] = $$order;
endforeach;
endforeach;
print_r($topOrders);
In $topOrders, you have an array that contains as key the ID, and as value you got the number of orders. All you have to do is to sort your array to get your top 3.
I have an array within an array, for example:
[
[0, 20, 5],
[5, 0, 15],
[5, 10, 0]
]
I need to get the max number in each column.
The max of [0 , 5 , 5] is 5, so that goes into the result array.
The max of [20, 0, 10] is 20, so that goes into the result array.
The max of [5, 15, 0] is 15, so that goes into the result array.
The final result array must contain [5, 20, 15].
First, the array has to be transposed (flip the rows and columns):
function array_transpose($arr) {
$map_args = array_merge(array(NULL), $arr);
return call_user_func_array('array_map', $map_args);
}
(taken from Is there better way to transpose a PHP 2D array? - read that question for an explanation of how it works)
Then, you can map the max function on the new array:
$maxes = array_map('max', array_transpose($arr));
Example: http://codepad.org/3gPExrhO
Output [I think this is what you meant instead of (5, 15, 20) because you said index 1 should be max of (20, 0, 10)]:
Array
(
[0] => 5
[1] => 20
[2] => 15
)
Without the splat operator, array_map() with max() will return the max value for each row. ([20, 15, 10])
With the splat operator to transpose the data structure, the max value for each column is returned.
Code: (Demo)
$array = [
[0, 20, 5],
[5, 0, 15],
[5, 10, 0]
];
var_export(
array_map('max', ...$array)
);
Output:
array (
0 => 5,
1 => 20,
2 => 15,
)