I walk around here with some hesitation, I have passed an array with sub elements (so to speak) and I need three random values but these are obtained without repeating.
The array is as follows:
Array
(
[0] => Array
(
[uid] => 1
[ticket_code] => 0oreb8yo
)
[1] => Array
(
[uid] => 1
[ticket_code] => 2oeii8hm
)
[2] => Array
(
[uid] => 1
[ticket_code] => m0dwtjiw
)
[3] => Array
(
[uid] => 1
[ticket_code] => q6c7cymb
)
[4] => Array
(
[uid] => 1
[ticket_code] => zyqhm5bj
)
[5] => Array
(
[uid] => 1
[ticket_code] => amdqzjpi
)
[6] => Array
(
[uid] => 2
[ticket_code] => tzql7l42
)
[7] => Array
(
[uid] => 2
[ticket_code] => gap0r6vf
)
[8] => Array
(
[uid] => 2
[ticket_code] => ypqum5yz
)
[9] => Array
(
[uid] => 4
[ticket_code] => smupluac
)
[10] => Array
(
[uid] => 4
[ticket_code] => 9d8jsha7
)
[11] => Array
(
[uid] => 5
[ticket_code] => 6hdnja42
)
)
And I need you to get 3 "ticket_code" but no right to repeat the "uid".
I've been on trying as follows, but also repeats the "uid".
$ticketsWinners = array();
for ($i=0; $i < 3; $i++) {
$aux = array_rand($allTickets);
$aux2 = $allTickets[$aux]['uid'];
$ticketsWinners[] = array(
'uid' => $aux2,
'ticket_code' => $allTickets[$aux]['ticket_code']
);
}
Any way to do it without repeats?
We thank you in advance if anyone knows of something ^^
Try something like:
$ticketsWinners = array();
while (sizeof($ticketsWinners) < 3) {
$aux = array_rand($allTickets);
// array_rand return array of keys so you need first value only
$uid = $allTickets[$aux[0]]['uid']
// add uid as a key so ass not tot check all $allTickets values
if (!isset($ticketsWinners[$uid]))
$ticketsWinners[$uid] = $allTickets[$aux[0]];
}
// if you need $allTickets back to numeric keys [0, 1, 2]
$allTickets = array_values($allTickets);
if you're afraid of infinite loops (that can take place really) then try this:
$ticketsWinners = array();
// shuffle array before checking
shuffle($allTickets);
foreach ($allTickets as $tick_data) {
$uid = $tick_data['uid'];
if (!isset($ticketsWinners[$uid]))
$ticketsWinners[$uid] = $tick_data;
if (sizeof($ticketsWinners) == 3)
break;
}
Here in worst case you check $allTickets array and get winners of size <= 3.
Try this:
$ticketsWinners = array();
$ticketUid = array();
for ($i=0; $i < 3; $i++) {
$aux = array_rand($allTickets);
$aux2 = $allTickets[$aux]['uid'];
if(! in_array($aux2, $ticketUid)) {
$ticketUid[$i] = $aux2;
$ticketsWinners[] = array(
'uid' => $aux2,
'ticket_code' => $allTickets[$aux]['ticket_code']
);
} else {
$i--;
}
}
this structure would be better ( added benefit of ticket numbers being unique )
$tickets = Array
(
'0oreb8yo' => 1,
'2oeii8hm' => 1,
'm0dwtjiw' => 1,
'q6c7cymb' => 1,
'zyqhm5bj' => 1,
'amdqzjpi' => 1,
'tzql7l42' => 2,
'gap0r6vf' => 2,
'ypqum5yz' => 2,
'smupluac' => 3,
'9d8jsha7' => 4,
'6hdnja42' => 5,
);
$winners = array();
$picks = 3;
for($i = 0; $i < $picks; $i++){
if(count($tickets) == 0 ){
break; //or error -- shouldn't need this unless picks exceed uids
}
$ticket = array_rand($tickets);
$winner = $tickets[$ticket];
$winners[] = $winner;
$tickets = array_filter($tickets, function($item) use ($winner){
return $winner != $item;
});
}
echo '<pre>';
var_export($winners);
outputs
array (
0 => 2,
1 => 1,
2 => 4,
)
array (
0 => 2,
1 => 1,
2 => 3,
)
array (
0 => 1,
1 => 3,
2 => 2,
)
unlike the while option, this will reduce the operations for each loop of the for loop by reducing the ticket array by the uid. It's also the only way to insure your not always pulling out a user with tickets, what if user 1 bought 90% of the tickets, you'd loop on him 90% of the time, in any case you have to reduce the ticket array by winners if they can win only once. In essence you remove each uid from the list when they win. You can also be sure that each ticket has the same chance to win ( as well as array_rand is random that is ) - they all have equal footing.
ticket array reduction
after loop1
array (
'tzql7l42' => 2,
'gap0r6vf' => 2,
'ypqum5yz' => 2,
'smupluac' => 3,
'9d8jsha7' => 4,
'6hdnja42' => 5,
)
after loop2
array (
'smupluac' => 3,
'9d8jsha7' => 4,
'6hdnja42' => 5,
)
after loop3
array (
'smupluac' => 3,
'6hdnja42' => 5,
)
winners
array (
0 => 1,
1 => 2,
2 => 4,
)
to return both the uid and wining ticket change
$winners[] = $winner;
to
$winners[$ticket] = $tickets[$ticket];
now winners will be, just like the input array
ticketnumber => uid
ticket is the key ( which is the ticket ) and winner is the value ( which is the uid )
Related
How to update an array of objects, adding the quantities if you already have the same ID, or if you have not created a new object.
I tried to explain in the code with the arrays and also with the idea of how I would like the result to be.
old Array
$a1 = [
array(
"id" => 1,
"qty" => 1
),
array(
"id" => 2,
"qty" => 1
)
];
$a2 = [
array(
"id" => 1,
"qty" => 1
)
];
$output = array_merge($a1, $a2);
echo '<pre>';
print_r($output);
echo '</pre>';
Result Error:
Array
(
[0] => Array
(
[id] => 1
[qty] => 1
)
[1] => Array
(
[id] => 2
[qty] => 1
)
[2] => Array
(
[id] => 1
[qty] => 1
)
)
What I need, in addition to if the ID does not contain, add.
Array
(
[0] => Array
(
[id] => 1
[qty] => 2
)
[1] => Array
(
[id] => 2
[qty] => 1
)
)
You can take the first array as base, then search for the key (if existing) where the product matches the id. Then either add the quantity and recalculate the price or you just add the reformatted element (id to product conversion).
$result = $a;
foreach($b as $element) {
$matchingProductIndex = array_search($element['id'], array_column($a, 'product'));
if ($matchingProductIndex !== false) {
$pricePerUnit = $result[$matchingProductIndex]['price'] / $result[$matchingProductIndex]['qty'];
$result[$matchingProductIndex]['qty'] += $element['qty'];
$result[$matchingProductIndex]['price'] = $result[$matchingProductIndex]['qty'] * $pricePerUnit;
} else {
$result[] = [
'qty' => $element['qty'],
'product' => $element['id'],
'price' => $element['price'],
];
}
}
print_r($result);
Working example.
Loop through both arrays with foreach and check the ids against each other.
https://paiza.io/projects/lnnl5HeJSFIOz_6KD6HRIw
<?php
$arr1 = [['qty' => 4, 'id' => 4],['qty' => 1,'id' => 30]];
$arr2 = [['id' => 30, 'qty' => 19],['id' => 31, 'qty' => 2]];
$arr3 = [];
foreach($arr1 as $iArr1){
$match = false;
foreach($arr2 as $iArr2){
if($iArr1['id'] === $iArr2['id']){
$arr3[] = ['id' => $iArr1['id'], 'qty' => $iArr1['qty'] + $iArr2['qty']];
$match = true;
}
}
if(!$match){
$arr3[] = $iArr1;
$arr3[] = $iArr2;
}
}
print_r($arr3);
?>
One approach could be one I more often suggested.
First lets merge $a2 with one to simplify looping over one larger collection.
If we then create a small mapping from id to its index in the result array we can update the running total of qty.
$map = [];
$result = [];
// Merge the two and do as per usual, create a mapping
// from id to index and update the qty at the corresponding index.
foreach (array_merge($a1, $a2) as $subarr) {
$id = $subarr['id'];
if (!key_exists($id, $map)) {
$index = array_push($result, $subarr) - 1;
$map[$id] = $index;
continue;
}
$result[$map[$id]]['qty'] += $subarr['qty'];
}
echo '<pre>', print_r($result, true), '</pre>';
Output:
Array
(
[0] => Array
(
[id] => 1
[qty] => 2
)
[1] => Array
(
[id] => 2
[qty] => 1
)
)
This is how my array looks like :
Array
(
[0] => Array
(
[unit] => 10
[harga] => 15000
)
[1] => Array
(
[unit] => 7
[harga] => 10000
)
[2] => Array
(
[unit] => 12
[harga] => 123123
)
)
I want to unset the 0 key array when the unit is 0 and rearrange the key so the 1 key will replace the 0.
This is how I do it :
$jumlah_penjualan = $data - > unit;
while ($jumlah_penjualan > 0) {
$persediaan_pertama = $persediaan[0]['unit'];
$harga_persediaan = $persediaan[0]['harga'];
if ($persediaan_pertama < $jumlah_penjualan) {
$dijual = $persediaan_pertama;
$penjualan[] = array(
'unit' => $dijual,
'harga' => $harga_persediaan,
'total' => $dijual * $harga_persediaan);
$persediaan[0]['unit'] = $persediaan[0]['unit'] - $dijual;
} else {
$dijual = $jumlah_penjualan;
$penjualan[] = array(
'unit' => $dijual,
'harga' => $harga_persediaan,
'total' => $dijual * $harga_persediaan);
$persediaan[0]['unit'] = $persediaan[0]['unit'] - $dijual;
}
if ($persediaan[0]['unit'] == 0) {
unset($persediaan[0]);
$persediaan = array_values($persediaan);
}
$jumlah_penjualan = $jumlah_penjualan - $dijual;
}
But the result looks like it continues looping before rearranging the array.
This is how the array should look like after unset:
Array(
[0] => Array
(
[unit] => 9
[harga] => 123123
)
)
If you want to remove the first elements until the unit is not 0, you can
$arr = array
(
array
(
"unit" => 0,
"harga" => 15000
),
array
(
"unit" => 0,
"harga" => 10000
),
array
(
"unit" => 12,
"harga" => 123123
)
);
while( $arr[0]["unit"] == 0 ) { //Loop until $arr[0]["unit"] is not 0
unset($arr[0]); //Remove $arr[0] since unit is 0
$arr = array_values($arr); //Make Make element 1 to element 0
}
echo "<pre>";
print_r( $arr );
echo "</pre>";
This will result to:
Array
(
[0] => Array
(
[unit] => 12
[harga] => 123123
)
)
To remove the first element of an array and reindex the elements, use array_shift. First, check that the number of units are zero, then remove the first element if that's the case.
if ($arr[0]['unit'] == 0) {
array_shift($arr);
}
Since it's impossible to say what your other variables even mean because of the language, you probably want to move this outside of your while loop, so that the first element is only removed after you've processed the array.
Given an array of arrays like this:
$array = array(
0 => array (
0 => 35,
1 => 30,
2 => 39
),
1 => array (
0 => 20,
1 => 12,
2 => 5
),
...
n => array (
0 => 10,
1 => 15,
2 => 7
),
);
I have the need to find the entry in the array which is closer to given parameters
find($a, $b, $c) {
//return the closer entry to the input
}
For closer entry I mean the entry which has closer values to the ones gave in input, e.g. passing (19, 13, 3) it should return $array[1]
The way in which I do the calculation at the moment is looping through the whole array, keeping a variable $distance which starts from -1, and a temporary $result variable. For each element I calculate the distance
$dist = abs( subarray[0] - $a ) + abs ( subarray[1] - $b ) + abs( subarray[2] - $c )
and if the calculated distance is equal to -1 or lower than the variable $distance which is out of the loop, I assign the new distance to the varaible and I save the corresponding array in the $result variable. At the end of the loop I end up having the value I need.
Also, one of the values can be empty: e.g. (19, 13, false) should still return $array[1] and the calculation should then ignore the missing parameter - in this case the distance is calculated as
$dist = abs( subarray[0] - $a ) + abs ( subarray[1] - $b );
ignoring the values of subarray[2] and $c.
The problem is, even if my code is working, it took too much time to execute as the size of the array can easily go up to many hundred thousands elements. We are still talking about milliseconds, but for various reasons this is still unacceptable.
Is there a more effective way to do this search in order to save some time?
A custom function - maybe there is a better way but check it out :
In a few words :
Search all the items and find in percentage the difference between the number it checks($mArray[0...3]) and the number you gave($mNumbersToFind[0...3]. Add all the three number's (of each element) possibilities - find the max - keep the position and return the array.
$array = array(
array (
0 => 13,
1 => 15,
2 => 4
),
array (
0 => 20,
1 => 12,
2 => 5
),
array (
0 => 13,
1 => 3,
2 => 15
),
);
$mNumbersToFind = array(13,3,3);
$mFoundArray = find($mNumbersToFind, $array);
echo "mFinalArray : <pre>";
print_r($mFoundArray);
function find($mNumbersToFind, $mArray){
$mPossibilityMax = count($mNumbersToFind);
$mBiggestPossibilityElementPosition = 0;
$mBiggestPossibilityUntilNow = 0;
foreach($mArray as $index => $current){
$maxPossibility = 0;
foreach($current as $subindex => $subcurrent){
$mTempArray[$index][$subindex]['value'] = $subcurrent - $mNumbersToFind[$subindex];
$percentChange = (1 - $mTempArray[$index][$subindex]['value'] / $subcurrent) * 100;
$mTempArray[$index][$subindex]['possibility'] = $percentChange;
$maxPossibility += $percentChange/$mPossibilityMax;
}
$mTempArray[$index]['final_possibility'] = $maxPossibility;
if($maxPossibility > $mBiggestPossibilityUntilNow){
$mBiggestPossibilityUntilNow = $maxPossibility;
$mBiggestPossibilityElementPosition = $index;
}
}
echo "mTempArray : <pre>"; // Remove this - it's just for debug
print_r($mTempArray); // Remove this - it's just for debug
return $mArray[$mBiggestPossibilityElementPosition];
}
Debug Output ($mTempArray) :
mTempArray :
Array
(
[0] => Array
(
[0] => Array
(
[value] => 0
[possibility] => 100
)
[1] => Array
(
[value] => 12
[possibility] => 20
)
[2] => Array
(
[value] => 1
[possibility] => 75
)
[final_possibility] => 65
)
[1] => Array
(
[0] => Array
(
[value] => 7
[possibility] => 65
)
[1] => Array
(
[value] => 9
[possibility] => 25
)
[2] => Array
(
[value] => 2
[possibility] => 60
)
[final_possibility] => 50
)
[2] => Array
(
[0] => Array
(
[value] => 0
[possibility] => 100
)
[1] => Array
(
[value] => 0
[possibility] => 100
)
[2] => Array
(
[value] => 12
[possibility] => 20
)
[final_possibility] => 73.333333333333
)
)
Final Output :
mFinalArray :
Array
(
[0] => 13
[1] => 3
[2] => 15
)
I basically used a concept of proximity (lesser distance total for each array) and returned that. The code was made in a way that can improve very well in so many routines.
PS: I didn't used advanced functions or other things because you are concerned about performance issues. It's most simplest routine I could did in a short period of time.
$array = array(
0 => array (
0 => 35,
1 => 30,
2 => 39
),
1 => array (
0 => 20,
1 => 12,
2 => 5
),
);
$user = array(19,13,3);
function find($referencial, $input){
$totalRef = count($referencial);
if (is_array($referencial)){
for ($i = 0; $i < $totalRef; $i++) {
if (is_array($referencial[$i])){
$totalSubRef = count($referencial[$i]);
$proximity = array();
for ($j = 0; $j < $totalSubRef; $j++) {
$proximity[$i] += abs($referencial[$i][$j] - $input[$j]);
}
if ($i > 0){
if ($maxProximity['distance'] > $proximity[$i]) {
$maxProximity['distance'] = $proximity[$i];
$maxProximity['index'] = $i;
}
} else {
$maxProximity['distance'] = $proximity[$i];
$maxProximity['index'] = $i;
}
}
}
return $maxProximity;
} else {
exit('Unexpected referencial. Must be an array.');
}
}
$found = find($array, $user);
print_r($found);
//Array ( [distance] => 4 [index] => 1 )
print_r($array[$found['index']]);
// Array ( [0] => 20 [1] => 12 [2] => 5 )
I have five strings:
$array_key = "f_name, f_qty, f_price, f_cur_date";
$food_name = "Meal for 2, Four Seasons Pizza, Lunch Deal, Pepsi";
$food_qty = "1, 3, 5, 7";
$food_price = "10, 30, 50, 70";
$food_userId = "1, 2, 3, 4";
I need some array like this:
Array (
[0] => Array (
[f_name] => Meal for 2
[f_qty] => 1
[f_price] => 10
[f_cur_date] => 1
)
[1] => Array (
[f_name] => Four Seasons Pizza
[f_qty] => 3
[f_price] => 30
[f_cur_date] => 2
)
[2] => Array (
[f_name] => Lunch Deal
[f_qty] => 5
[f_price] => 50
[f_cur_date] => 3
)
[3] => Array (
[f_name] => Pepsi
[f_qty] => 7
[f_price] => 70
[f_cur_date] => 4
))
I convert strings to array with "explode":
$array_key_parts = explode(",",$array_key);
$food_name_parts = explode(",",$food_name);
$food_qty_parts = explode(",",$food_qty);
$food_price_parts = explode(",",$food_price);
$food_price_parts = explode(",",$food_price);
But don't know how to customize it further.
Basically, I'm getting this strings from query GROUP_CONCAT to use it in fullcalendar.js.
You can make an array using array_map function like below :
$food_name_parts = explode(",",$food_name);
$food_qty_parts = explode(",",$food_qty);
$food_price_parts = explode(",",$food_price);
$array_key_parts = explode(",",$array_key);
$myarray = array_map(function ($f_name, $f_qty, $f_price) {
return compact('f_name','f_qty','f_price');
}, $food_name_parts, $food_qty_parts, $food_price_parts);
echo "<pre>";
print_r($myarray);
I have an array that's output is this:
Array ( [winners] =>
Array ( [0] => Gold Member
[1] => CROTCH SNIFFER
[2] => TEAM #1 )
[prizeTotal] => 20 )
Array ( [winners] =>
Array ( [0] => TEAM #1
[1] => CROTCH SNIFFER )
[prizeTotal] => 60 )
Array ( [winners] =>
Array ( [0] => Gold Member
[1] => TEAM #1 )
[prizeTotal] => 30 )
Array ( [winners] =>
Array ( [0] => TEAM #1
[1] => TEAM #2
[2] => SCREW-NUT-BOLT )
[prizeTotal] => 90 )
Please forgive the names...it's not my DB.
I can not change the way the array is show here.
With that being said how can I group and sum?
1. For each winners array there is a prizeTotal below the team names. That prize total should be the value of each teamName above it.
Example
Array ( [winners] =>
Array ( [0] => Gold Member
[1] => CROTCH SNIFFER
[2] => TEAM #1 )
[prizeTotal] => 20 )
Gold Member should have 20
CROTCH SNIFFER should have 20
TEAM #1 should have 20 AND
Array ( [winners] =>
Array ( [0] => TEAM #1
[1] => CROTCH SNIFFER )
[prizeTotal] => 60 )
TEAM #1 should have 60
CROTCH SNIFFER sould have 60....etc....
Then I want to group by team name and sum so that I can display...
CROTCH SNIFFER = 80
Gold Member = 50
TEAM #1 = 200
Team #2 = 90.
Thanks in advance...
Assuming you can collect all your arrays into one i.e. :
$arrays = array($array1,$array2,....,$arrayn);
then
$grouping = array();
foreach($arrays AS $array)
{
foreach($array['winners'] AS $k=>$v)
{
//check if the array key is a number, will contain a team, and if that
//them is not alreay listed
if(is_numeric($k) && !array_key_exists($v,$grouping))
$grouping[$v] = 0;
//sum the prize to the team's sum
$grouping[$v] += intval($array['winners']['prizeTotal']);
}
}
//the following is just for debugging
print_r($grouping);
this should produce something like:
$grouping[TEAM #1] = 200
$grouping[TEAM #2] = 90
$grouping[CROTCH SNIFFER] = 200
...
You need to make a new array to hold your results, then for each of your existing arrays, check if you're already processed one for that team
If you have, then simply add the prizeTotal to the prizeTotal stored in your new array's entry for that team.
If not, simply add the team's entry to your new array.
I have made a function that imitates mysql SUM() and GROUP BY. I hope it will fit your needs:
$in_a = array(
array("a" => 0,"b"=>0,"s"=> 1),
array("a" => 0,"b"=>0,"s"=> 2),
array("a" => 1,"b"=>1,"s"=> 1),
array("a" => 0,"b"=>1,"s"=> 1),
array("a" => 0,"b"=>1,"s"=> 1),
array("a" => 1,"b"=>0,"s"=> 1),
array("a" => 0,"b"=>1,"s"=> 1),
array("a" => 1,"b"=>1,"s"=> 1),
array("a" => 1,"b"=>0,"s"=> 1),
);//input array exaple
$group_by_a = array("a","b");//input array will be grouped by these
$sum_a = array("s"); //'s' values of input will be summed
$out_a = array(); //this is the output array
foreach($in_a as $in_i => $in)
{
$add = false;
foreach($out_a as $out_i => $out)
{
$add = true;
foreach($group_by_a as $group_by)
if($in[$group_by] != $out[$group_by])
{
$add = false;
break;
}
if($add)
{
foreach($sum_a as $sum)
$out_a[$out_i][$sum] += $in[$sum];
break;
}
}
if(!$add)
{
foreach($group_by_a as $group_by)
$out_a[$in_i][$group_by] = $in[$group_by];
foreach($sum_a as $sum)
$out_a[$in_i][$sum] = $in[$sum];
}
}
the result:
Array
(
[0] => Array
(
[a] => 0
[b] => 0
[s] => 3
)
[2] => Array
(
[a] => 1
[b] => 1
[s] => 2
)
[3] => Array
(
[a] => 0
[b] => 1
[s] => 3
)
[5] => Array
(
[a] => 1
[b] => 0
[s] => 2
)
)