PHP Group by value and sort randomly - php

I want to group an associative array by value and randomize the items per group.
I have the following array $result
Aray(
[0] => Building Object
(
[id] => 285
[formula] => 4
[title] => test 1
)
[1] => Building Object
(
[id] => 120
[formula] => 4
[title] => test 2
)
[2] => Building Object
(
[id] => 199
[formula] => 2
[title] => test 3
)
[3] => Building Object
(
[id] => 231
[formula] => 1
[title] => test 4
)
[3] => Building Object
(
[id] => 230
[formula] => 1
[title] => test 5
)
)
So I want to group the array by its formula so the objects with formula 4 should be on top. But the buildings should be per group random so first id 285 on top then id 120 on top... So I want randomly
Aray(
[0] => Building Object
(
[id] => 285
[formula] => 4
[title] => test 1
)
[1] => Building Object
(
[id] => 120
[formula] => 4
[title] => test 2
) ..
How can I do this I tried:
shulffle($result);
usort($result, "cmp");
But that doesn't keep my array grouped by the formula.

usort is the right function, but you need to be more specific:
// drop the `shuffle`, we'll be shuffling in the sort
usort($result,function($a,$b) {
// PHP 5.4 or newer:
return ($a->formula - $b->formula) ?: rand(-1,1);
// older PHP:
if( $a->formula == $b->formula) return rand(-1,1);
return $a->formula - $b->formula;
});
And before people say my shuffling "isn't really random", I say "it's random enough for this application".

Related

php combine two array's subarrays where value of certain key is equal

Hello & thanks for your interest
I do have two arrays:
[A] -from the mysql query of one database on server1- the
$postings_array - a SELECT of all postings of a discussion-thread
(based on the thread's id)
[B] -from the mysql query of an other database on server2 - the
$usersdata_array - a SELECT of all postings of a discussion-thread
(based on the thread's id)
This means:
in [A] there are many postings-sub-arrays and in [B] one or more
userdata-sub-arrays.
both arrays always do include a key named usrsID in each of their
subarrays.
I need to extend the Sub-Arrays in $postings_array [A]
by merging them
with the Sub-Arrays of the $usersdata_array [B]
based on WHERE the VALUE of the usrsID KEY in the sub-array[A] is EQUAL to the usrsID KEY in the sub-array[B].
EXAMPLE:
Array [A]:
(
[0] => Array
(
[ID] => 5
[usrsID] => 3
[tid] => 19
[txtid] => 22
)
[1] => Array
(
[ID] => 6
[usrsID] => 1
[tid] => 19
[txtid] => 23
)
[2] => Array
(
[ID] => 7
[usrsID] => 2
[tid] => 19
[txtid] => 24
)
[3] => Array
(
[ID] => 8
[usrsID] => 1
[tid] => 19
[txtid] => 25
)
)
--
Array [B]:
(
[0] => Array
(
[id] => 1
[usrsID] => 1
[avatarID] => 1
)
[1] => Array
(
[id] => 2
[usrsID] => 2
[avatarID] => 3
)
[2] => Array
(
[id] => 3
[usrsID] => 3
[avatarID] => 22
)
)
needed result (the by [B] extended [A] for the example above):
Array [A_extended]:
(
[0] => Array
(
[ID] => 5
[usrsID] => 3
[tid] => 19
[txtid] => 22
[id] => 3
[avatarID] => 22
)
[1] => Array
(
[ID] => 6
[usrsID] => 1
[tid] => 19
[txtid] => 23
[id] => 1
[avatarID] => 1
)
[2] => Array
(
[ID] => 7
[usrsID] => 2
[tid] => 19
[txtid] => 24
[id] => 2
[avatarID] => 3
)
[3] => Array
(
[ID] => 8
[usrsID] => 1
[tid] => 19
[txtid] => 25
[id] => 1
[avatarID] => 1
)
)
... I think, it's a common problem so there should be a best-practice around (may be in one inbuild php function or a combination of two or three of them) - and I do not have to reinvent the wheel.
At least, I hope so...
else, my approach would be
check the amounts of iterations (= the subarrays found in the $usersdata_array [B] )
iterate over the outerHaystack and trigger a function when $needle was found in innerHaystack
perform merge via checkSubArrayfunc
Approach,
with hayStackArray = complete [A]Array;
needle = $usrsID value of [B] Sub-Array:
function checkSubArrayfunc($hayStackSubArray, $needle, $toMergeSubArray) {
if (in_array(array('$hayStackSubArray'), $needle)) {
array_merge_recursive($hayStackSubArray, $toMergeSubArray);
}
}
Try this:
foreach($arr_b as $b_item) {
foreach($arr_a as $key => &$a_item) {
if ($b_item['usrsID'] == $a_item['usrsID']) {
$a_item['id'] = $b_item['usrsID'];
$a_item['avatarID'] = $b_item['avatarID'];
}
}
}
Your output of $_arr_a will be:
Array
(
[0] => Array
(
[ID] => 5
[usrsID] => 3
[tid] => 19
[txtid] => 22
[id] => 3
[avatarID] => 22
)
[1] => Array
(
[ID] => 6
[usrsID] => 1
[tid] => 19
[txtid] => 23
[id] => 1
[avatarID] => 1
)
[2] => Array
(
[ID] => 7
[usrsID] => 2
[tid] => 19
[txtid] => 24
[id] => 2
[avatarID] => 3
)
[3] => Array
(
[ID] => 8
[usrsID] => 1
[tid] => 19
[txtid] => 25
[id] => 1
[avatarID] => 1
)
)
At first take an empty array for store marged array. then traversed in both array. if the userID are be same in both the array of element then marge these array and push in margeArr.
$margeArr = [];
foreach($Array_A as $a){
foreach($Array_B as $b){
if($a['usrsID'] == $b['usrsID']){
array_push($margeArr,array_merge($a,$b));
}
}
}
print_r($margeArr);
Comment by the questionaire:
It's a great solution - it really meets the requirements described in my question and merges the to be marged Array with the key-value-pairs of the "to be injected"-Array.
But I prefere the bestprogrammersinintheworld's solution, where I can rename the keys "en passant / on-the-fly":
foreach($arr_b as $b_item) {
foreach($arr_a as $key => &$a_item) {
if ($b_item['usrsID'] == $a_item['usrsID']) {
$a_item['myNewKeyName1'] = $b_item['usrsID'];
$a_item['myNewKeyName2'] = $b_item['avatarID'];
}
}
}
print("<pre>".print_r($arr_a,true)."</pre>");
Sorting my advice from best to worst...
Joining this data should be done before PHP is necessary. Depending on the location of the two sources, this may be trivial, but JOINing via SQL is the best, most direct, most professional option. These links may be helpful:
access two different databases on different servers in the same query
Joining Tables from different Database
In lieu of option 1, declare and leverage a lookup array (in PHP) which would have the identifying column as its first level keys. Then you don't need to nest another loop to relate the two data sets.
$lookup = array_column($arrayB, null, 'usrsID');
foreach ($arrayA as $row) {
$result[] = $row + ($lookup[$row['usrsID']] ?? []);
}
The worst option which I do NOT recommend is writing a nested loop with a condition inside of it. All previous answers are doing this -- and slowing down an already inefficient approach, they don't even break inside the condition block.

PHP/Guzzle Target parent element

I have an app using guzzle/php to make requests to a rest service.
When it yields a response, it includes nested arrays and objects:
[exampleBalances] => Array (
[0] => stdClass Object (
[balance] => 6
[name] => Prize One
[prizeCode] => 38
)
[1] => stdClass Object (
[balance] => 5
[name] => Prize Two
[prizeCode] => 20
)
[2] => stdClass Object (
[balance] => 4
[name] => Prize Four
[prizeCode] => 39
)
)
Until now Ive been pulling the value based on the order:
$prizeThree = $response->exampleBalances['3']->balance;
However, the service wont display any 'prizes' if the customer has 0, so the example above would no longer be accurate if a new item was added:
[exampleBalances] => Array (
[0] => stdClass Object (
[balance] => 6
[name] => Prize One
[prizeCode] => 38
)
[1] => stdClass Object (
[balance] => 5
[name] => Prize Two
[prizeCode] => 20
)
[2] => stdClass Object (
[balance] => 8
[name] => Prize Three
[prizeCode] => 54
)
[3] => stdClass Object (
[balance] => 4
[name] => Prize Four
[prizeCode] => 39
)
)
Is there a way to target the correct element, without using the order that it appears in the response?
I could not find any documentation, but its difficult to convey the issue. I was thinking there may be someway to create a condition to check an elements inner values (preferably the 'prize code') Any help would be greatly appreciated.
In PHP 5.5.0 or newer, you can use the array_column() function to do this search:
$index = array_search($prizeCodeSearch, array_column($exampleBalances, 'prizeCode'));
$element = $exampleBalances[$index];

PhP - Search massive array for value, return parent key.

Q: How to Search Massive Multi-Dimensional Array for Single Value, and Return Parent Array?
I have this massive json that represents all of the achievements in WoW.
http://us.battle.net/api/wow/data/character/achievements
I converted it into an array using json_decode. This then leaves me with a very massive array that I need to search all of its levels until I find a specific value, I then need to return the parent array of that value.
ex:
This is one small part of the decoded array.
[0] => Array
(
[id] => 7385
[title] => Pub Crawl
[points] => 10
[description] => Complete the Brewmaster scenario achievements listed below.
[reward] => Reward: Honorary Brewmaster Keg
[rewardItems] => Array
(
[0] => Array
(
[id] => 87528
[name] => Honorary Brewmaster Keg
[icon] => inv_holiday_brewfestbuff_01
[quality] => 3
[itemLevel] => 90
[tooltipParams] => Array
(
)
[stats] => Array
(
)
[armor] => 0
)
)
[icon] => inv_misc_archaeology_vrykuldrinkinghorn
[criteria] => Array
(
[0] => Array
(
[id] => 20680
[description] => Spell No Evil
[orderIndex] => 0
[max] => 1
)
[1] => Array
(
[id] => 20681
[description] => Yaungolian Barbecue
[orderIndex] => 1
[max] => 1
)
[2] => Array
(
[id] => 20682
[description] => Binan Village All-Star
[orderIndex] => 2
[max] => 1
)
[3] => Array
(
[id] => 20683
[description] => The Keg Runner
[orderIndex] => 3
[max] => 1
)
[4] => Array
(
[id] => 20684
[description] => Monkey in the Middle
[orderIndex] => 4
[max] => 1
)
[5] => Array
(
[id] => 20685
[description] => Monkey See, Monkey Kill
[orderIndex] => 5
[max] => 1
)
[6] => Array
(
[id] => 20686
[description] => Don't Shake the Keg
[orderIndex] => 6
[max] => 1
)
[7] => Array
(
[id] => 20687
[description] => Party of Six
[orderIndex] => 7
[max] => 1
)
[8] => Array
(
[id] => 20688
[description] => The Perfect Pour
[orderIndex] => 8
[max] => 1
)
[9] => Array
( re
[id] => 20689
[description] => Save it for Later
[orderIndex] => 9
[max] => 1
)
[10] => Array
(
[id] => 20690
[description] => Perfect Delivery
[orderIndex] => 10
[max] => 1
)
)
[accountWide] =>
[factionId] => 2
)
I am attempting to create a function where I can just simply enter the achievement ID, which in this exmple is 7385, and have the parent array which would be [0] => Array (...); returned, so i can then grab the achievement details from that array.
I am not sure if this is really a proper question, as I am not sure as where to start.
So far I have just started breaking the original massive array down into its 10 equally as massive categories, and then searching them each individually, but I would like to just be able to search the main array once instead of searching each category array individually.
ex:
$allAchieves = file_get_contents('http://us.battle.net/api/wow/data/character/achievements');
$allAchieves = json_decode($allAchieves, true);
$generalAchieves = $allAchieves[achievements][0][achievements];
$quests = $allAchieves[achievements][1][categories];
$explorationAchieves = $allAchieves[achievements][2][categories];
$pvp = $allAchieves[achievements][3][categories];
$dungeonAndRaids = $allAchieves[achievements][4][categories];
$professions = $allAchieves[achievements][5][categories];
$reputation = $allAchieves[achievements][6][categories];
$scenarios = $allAchieves[achievements][7][categories];
$worldEvents = $allAchieves[achievements][8][categories];
$petbattle = $allAchieves[achievements][9][categories];
$featsOfStrength = $allAchieves[achievements][10][categories];
Hopefully someone can help, as the other threads I have seen sofar on array searching seem too simple to be of any help as the arrays they are dealing with are nothing to the size of the one I have here.
Thanks for the suggestions, but I solved the issue using a different approach found here:
http://us.battle.net/wow/en/forum/topic/8892160022?page=1#4

Sorting Multidimensional Array by Specific Key

EDIT: For anyone who might come across this post with a similar problem, It was solved by taking konforce's supplied answer and tweaking around a bit with the custom sorting function:
function cmp($a, $b) {
if ($a[5] == $b[5]) {
return ($a[3] < $b[3]) ? -1 :1;
}
return ($a[5] > $b[5]) ? -1 : 1;
}
Notice $a[5] == $b[5] does not return zero. It was changed to check who has the most losses and then sort it in ASC order. I'm sure you can even keep going and add another if-statement in there in-case they have the same losses.
Lastly, all you do is usort($ARRAY, "cmp"); and finito!!!
Original Post
My apologies for coming up with yet another MD Array sorting question but I'm just not getting it. I've searched aplenty
for a solution and although many sites have provided what seemed like a logical answer I still have not been able to figure it out.
My problem is since I'm still learning its been rather difficult for me to grasp the concept of using usort with a custom comparing
function. Atleast, thats what I have seen the most when others have tried to sort MD Arrays.
I'm working on a small project to sharpen up on my php skills. Its a very basic tournament standings script that holds a team's information within an array. I would like to sort the array by most points($array[X][X][5]).
So the array looks something like this:
Array (
[0] => Array (
[0] => Array (
[0] => cooller
[1] => 6
[2] => 6
[3] => 0
[4] => 0
[5] => 18
)
)
[1] => Array (
[0] => Array (
[0] => strenx
[1] => 9
[2] => 5
[3] => 1
[4] => 3
[5] => 18
)
)
[2] => Array (
[0] => Array (
[0] => rapha
[1] => 10
[2] => 8
[3] => 1
[4] => 1
[5] => 25
)
) [3] => Array (
[0] => Array (
[0] => ronald reagan
[1] => 5
[2] => 4
[3] => 0
[4] => 1
[5] => 13
)
)
)
I would like to sort it by most points(cell #5), so it would look like this after sorting:
Array (
[0] => Array (
[0] => Array (
[0] => rapha
[1] => 10
[2] => 8
[3] => 1
[4] => 1
[5] => 25
)
)
[1] => Array (
[0] => Array (
[0] => cooller
[1] => 6
[2] => 6
[3] => 0
[4] => 0
[5] => 18
)
)
[2] => Array (
[0] => Array (
[0] => strenx
[1] => 9
[2] => 5
[3] => 1
[4] => 3
[5] => 18
)
)
[3] => Array (
[0] => Array (
[0] => ronald reagan
[1] => 5
[2] => 4
[3] => 0
[4] => 1
[5] => 13
)
)
)
The player with 25 points would be at the top, followed by 18, 18, and lastly 13. Sorry for my earlier post, was having difficulty wording my question correctly. Thanks in advanced!
I think you want something like this:
usort($standings, function($a, $b) { return $b[0][5] - $a[0][5]; });
Or prior to PHP 5.3:
function cmp($a, $b) { return $b[0][5] - $a[0][5]; }
usort($standings, 'cmp');
When using usort, the $a and $b parameters will be one "layer" into the supplied array. So in your case, an example of $a or $b will be:
[0] => Array (
[0] => cooller
[1] => 6
[2] => 6
[3] => 0
[4] => 0
[5] => 18
)
I'm not sure why you have an extra containing array there, but as you can see, you want to sort based on the [0][5] position.
usort($standings[0][0][5], 'cmp') won't work because the first parameter isn't an array to sort, it's just a single number, the points.

multi dimensional array in random order

I want to make it so that my multi dimensional array is in a random order. How would you do it?
// This is how the array looks like
print_r($slides);
Array
(
[0] => Array
(
[id] => 7
[status] => 1
[sortorder] => 0
[title] => Pants
)
[1] => Array
(
[id] => 8
[status] => 1
[sortorder] => 0
[title] => Jewels
)
[2] => Array
(
[id] => 9
[status] => 1
[sortorder] => 0
[title] => Birdhouse
)
[3] => Array
(
[id] => 10
[status] => 1
[sortorder] => 0
[title] => Shirt
)
[4] => Array
(
[id] => 11
[status] => 1
[sortorder] => 0
[title] => Phone
)
)
// This how the result is if I use array_rand()
print_r(array_rand($slides, 5));
Array
(
[0] => 0
[1] => 1
[2] => 2
[3] => 3
[4] => 4
)
// This how the result is if I use shuffle()
print_r(shuffle($slides));
1
shuffle() is the way to go here. It prints 1 because shuffle changes the array in-place and returns a boolean, as it is written in the documentation:
Returns TRUE on success or FALSE on failure.
I suggest to also read the documentation of array_rand():
Picks one or more random entries out of an array, and returns the key (or keys) of the random entries.
Always read documentation if you use built-in functions. Don't just assume how the work. I bet it took more time to write the question than looking this up.
Instead of
print_r(shuffle($slides));
do
shuffle($slides);
print_r($slides);
You see shuffle() shuffles the array in-place
i am not sure how you want it to display but you can loop the array and use php rand(0,arraylen) function to parse the array.
It works perfect. print_r(shuffle($slides))) gives the output of TRUE, since the return value of shuffle is a boolean and not an array.
See the working example here: http://codepad.org/B5SlcjGf

Categories