Sorting objects in array - php

I have an array of objects containing a number of values. The values are set correctly and the data inside this array is also shown in correct way accoring to the order of objects.
What i would want now ii that the order is changed. In this particular example according to the objects 'Point' value, so the objects with the highest Pointvalue is first and so on...
What I tried to do was finding the object with the highest value, push it in the array and unsetting the original value. And with array_slice getting the relevant array elements in the end.
I also succeeded in the first part, but the problem is I keep finding the same object, so i somehow doesn't remove it from the array.
$max = $obj[0];
for ($j =0; $j<count($obj)-$j; $j++) {
for ($i=0; $i<count($names); $i++) {
if ($max->Point < $obj[$i+1]->Point) {
$max = $obj[$i+1];
}
}
if ($max->id == $obj[$j]->id) {
unset($obj[$j]);
}
array_push($obj, $max);
}
I'm not sure you can see through the code and what I'm trying to do, but hopefully someone can and either show my mistake(s), or show others way to accomplish the same?

Try using the usort() function. It allows you to sort the array according to a comparison function that you define.
function lower_points($a, $b) {
if ($a->Point == $b->Point) return 0;
else if ($a->Point > $b->Point) return -1;
else return 1;
}
usort($array_of_objects, lower_points);

Related

Foreach loop over array of objects Laravel

I'm receiving this array of objects and need to iterate over it, but the problem is that I need to get the value of the next item when its iterating, to compare the value of the current object with the next one, and if it's a different value, split this array in two.
So, I was doing it with next() php function:
//looking for the next register in the array
$next = next($finances);
//first array if exist different values
$aiuaEd = [];
//second array if exist different values
$aiua = [];
foreach ($finances as $finance) {
if ($finance->cnpj <> $next->cnpj) {
$aiua[] = $finance;
} else {
$aiuaEd[] = $finance;
}
}
This code works fine at some point, but then I got this error:
Trying to get property 'cnpj' of non-object in
I don't know why sometimes works well and sometimes don't, debugging this variables, I found that if my array have 2 objects inside only, when I'm looping over it, the $next->cnpj variable came as empty, and sometimes don't.
Can someone help me with this?
I solved it with a different approach, instead of using php next(), I first loop over this array saving the cnpj's into an array.
$cnpjs = [];
foreach($finances as $finance){
$cnpj[] = $finance->cnpj;
}
Then I use array_unique() to group this 2 differents CNPJ's and sort() to get the correct keys order.
//grouping cnpjs as unique, should exist only 2 keys
$cnpj = array_unique($cnpj);
//sort array keys to get in order
sort($cnpj);
Then I iterate over my $finances array again, but now I'm counting if this $cnpj array has more than 2 positions, which means that I have to split this data in two differents arrays.
foreach($finances as $finance){
if(count($cnpj) > 1){
if($finance->cnpj == $cnpj[1]){
$aiua[] = $finance;
}else{
$aiuaEd[] = $finance;
}
}else{
$aiuaEd[] = $finance;
}
}
I'm pretty sure that this is not the best approach for that problem, or at least the most optimized one, so I'm open for new approach's suggestions!
Just posting how I solved my problem in case anyone having the same one.
Notice that this approach is only usable because I know that will not exist more than 2 different's CNPJ's in the array.

Find index of value in associative array in php?

If you have any array $p that you populated in a loop like so:
$p[] = array( "id"=>$id, "Name"=>$name);
What's the fastest way to search for John in the Name key, and if found, return the $p index? Is there a way other than looping through $p?
I have up to 5000 names to find in $p, and $p can also potentially contain 5000 rows. Currently I loop through $p looking for each name, and if found, parse it (and add it to another array), splice the row out of $p, and break 1, ready to start searching for the next of the 5000 names.
I was wondering if there if a faster way to get the index rather than looping through $p eg an isset type way?
Thanks for taking a look guys.
Okay so as I see this problem, you have unique ids, but the names may not be unique.
You could initialize the array as:
array($id=>$name);
And your searches can be like:
array_search($name,$arr);
This will work very well as native method of finding a needle in a haystack will have a better implementation than your own implementation.
e.g.
$id = 2;
$name= 'Sunny';
$arr = array($id=>$name);
echo array_search($name,$arr);
Echoes 2
The major advantage in this method would be code readability.
If you know that you are going to need to perform many of these types of search within the same request then you can create an index array from them. This will loop through the array once per index you need to create.
$piName = array();
foreach ($p as $k=>$v)
{
$piName[$v['Name']] = $k;
}
If you only need to perform one or two searches per page then consider moving the array into an external database, and creating the index there.
$index = 0;
$search_for = 'John';
$result = array_reduce($p, function($r, $v) use (&$index, $search_for) {
if($v['Name'] == $search_for) {
$r[] = $index;
}
++$index;
return $r;
});
$result will contain all the indices of elements in $p where the element with key Name had the value John. (This of course only works for an array that is indexed numerically beginning with 0 and has no “holes” in the index.)
Edit: Possibly even easier to just use array_filter, but that will not return the indices only, but all array element where Name equals John – but indices will be preserved:
$result2 = array_filter($p, function($elem) {
return $elem["Name"] == "John" ? true : false;
});
var_dump($result2);
What suits your needs better, resp. which one is maybe faster, is for you to figure out.

Prepend to array, but keep the indexes with PHP

I have an array that are already sorted.
Now I would like to take all the arrays that have a sub array value 0 and put them at the start of the array.
This is what I tried to do:
foreach($dealStatsArray as $deal_id => $dealStats)
{
if($dealStats['revenueY'] == 0)
{
$tmpArray[$deal_id] = $dealStats; // Store the array
unset($dealStatsArray[$deal_id]); // Unset the current one, since it is not in right position
array_unshift($dealStatsArray, $tmpArray); // Prepend the tmp array, to have it at the beginning of the array
}
}
Now problem is that array_unshift() does:
"All numerical array keys will be modified to start counting from zero" -php net array_unshift()
Which mess up the rest of the code I got because I need to keep the indexes on $dealStatsArray, and the index for the new prepended array should be the $deal_id and not 0.
How can I do this? And I need a solution that can manage to prepend 2 or 3 times to the beginning of the array, just like it works fine with array_push (appending) I would like to do that, but just prepending
Update: Here is my currently uasort function, that are sorting the array after the revenueY value, so that the highest number are in the start of the array and then descending..
function cmp($a, $b)
{
if (($a["revenueY"]) == ($b["revenueY"])) {
return 0;
}
return (($a["revenueY"]) > ($b["revenueY"])) ? -1 : 1;
}
uasort($dealStatsArray, "cmp");
Now if I follow #thaJeztah's answer, which partly works, then I added this under:
function sortbyRevenueY($a, $b) {
if ($a['revenueY'] == $b['revenueY']) {
return 0;
}
return ($a['revenueY'] == 0) ? -1 : 1;
}
uasort($dealStatsArray, 'sortbyRevenueY');
But this does not work correct, It does take all the revenueY==0 arrays and prepend at the beginning of the array, but then the rest of the arrays gets unsorted (highest to lowest, the first uasort())
Here's my final goal: To have an array where all the revenueY==0 are at the beginning of the array, and after these the top revenue are coming after and then descending to lowest revenue at the end of the array.
You can probably achieve this by 'sorting' the array using a custom callback and uasort();
http://www.php.net/manual/en/function.uasort.php
function sortbyRevenueY($a, $b) {
if ($a['revenueY'] == $b['revenueY']) {
return 0;
}
if (0 == $a['revenueY']) {
return -1;
}
if (0 == $b['revenueY']) {
return 1;
}
return (($a["revenueY"]) > ($b["revenueY"])) ? -1 : 1;
}
uasort($dealStatsArray, 'sortbyRevenueY');
print_r($dealStatsArray);
Haven't been able to test it and the 'callback' method may need some tweaking, however, uasort() allows you to sort an array using a custom 'callback' method that determines 'how' the array should be sorted. The values inside the array will be sorted, without losing the key/value relation.
My example is just to illustrate how you can achieve this, but, as mentioned, may need to be tweaked.
[update]
I've updated by example to attempt to combine 'regular' sorting and sorting by '0' into a single callback. Again untested, but maybe this work. Please test this updated example.
You could try merging the arrays instead of unshifting:
$dealStatsArray = array_merge($tmpArray, $dealStatsArray);
So no matter how many items $tmpArray will have, they will be at the beginning

custom order and display foreach PHP

Thanks to the many folks who help us out here on Stackoverflow. You all are awesome! Now to the question. I've got an array for the following values: "duck", "chicken","egg", "pork", "steak", "beef", "fish", "shrimp", "deer", and "lamb."
I've gotten the list to display in Alphabetical order. This is a dynamic array, so it may not always have all these values or be in that order. I'd like to have "Steak" always appear first with "Top Choice" next to it, while keeping the rest in alphabetical order with "Available for Order" next to them.
Here's what I've got thus far with $meat_items as the array:
foreach($meat_items as $meat_item)
echo $meat_item . ' Available for Order <br>';
I should clarify: Steak may NOT always be a part of the array.
Since you always want steak to appear first, hard code it:
if (in_array("steak", $meat_items)) {
`echo "Steak: Top Choice";`
}
Sort your array alphabetically:
sort($meat_items);
Then loop through your array, echoing all items except the steak:
foreach ($meat_items as $meat_item) {
if ( "steak" != $meat_item ) {
echo $meat_item . ' Available for Order<br />';
}
}
if (!empty($meat_items['steak']))
{
echo 'Steak Top Choice <br >';
unset($meat_items['steak']);
}
sort($meat_items);
foreach($meat_items as $meat_item)
echo $meat_item . ' Available for Order <br>';
A more general purpose way to do this is to tell PHP how to sort the items, by defining a sorting "comparison" that prefers the "top choices", and then passing it to usort.
I don't really know PHP, but something like:
function prefer_top($a, $b) {
/* We can modify this array to specify whatever the top choices are. */
$top_choices = array('Steak');
/* If one of the two things we're comparing is a top choice and the other isn't,
then it comes first automatically. Otherwise, we sort them alphabetically. */
$a_top = in_array($a, $top_choices);
$b_top = in_array($b, $top_choices);
if ($a_top && !$b_top) { return -1; }
if ($b_top && !$a_top) { return 1; }
if ($a == $b) { return 0; }
return ($a < $b) ? -1 : 1;
}
usort($meat_items, "prefer_top");
// and then output them all in order as before.

Keeping an array sorted in PHP

I have a PHP script which reads a large CSV and performs certain actions, but only if the "username" field is unique. The CSV is used in more than one script, so changing the input from the CSV to only contain unique usernames is not an option.
The very basic program flow (which I'm wondering about) goes like this:
$allUsernames = array();
while($row = fgetcsv($fp)) {
$username = $row[0];
if (in_array($username, $allUsernames)) continue;
$allUsernames[] = $username;
// process this row
}
Since this CSV could actually be quite large, it's that in_array bit which has got me thinking. The most ideal situation when searching through an array for a member is if it is already sorted, so how would you build up an array from scratch, keeping it in order? Once it is in order, would there be a more efficient way to search it than using in_array(), considering that it probably doesn't know the array is sorted?
Not keeping the array in order, but how about this kind of optimization? I'm guessing isset() for an array key should be faster than in_array() search.
$allUsernames = array();
while($row = fgetcsv($fp)) {
$username = $row[0];
if (isset($allUsernames[$username])) {
continue;
} else {
$allUsernames[$username] = true;
// do stuff
}
}
The way to build up an array from scratch in sorted order is an insertion sort. In PHP-ish pseudocode:
$list = []
for ($element in $elems_to_insert) {
$index = binary_search($element, $list);
insert_into_list($element, $list, $index);
}
Although, it might actually turn out to be faster to just create the array in unsorted order and then use quicksort (PHP's builtin sort functions use quicksort)
And to find an element in a sorted list:
function binary_search($list, $element) {
$start = 0;
$end = count($list);
while ($end - $start > 1) {
$mid = ($start + $end) / 2;
if ($list[$mid] < $element){
$start = $mid;
}
else{
$end = $mid;
}
}
return $end;
}
With this implementation you'd have to test $list[$end] to see if it is the element you want, since if the element isn't in the array, this will find the point where it should be inserted. I did it that way so it'd be consistent with the previous code sample. If you want, you could check $list[$end] === $element in the function itself.
The array type in php is an ordered map (php array type). If you pass in either ints or strings as keys, you will have an ordered map...
Please review item #6 in the above link.
in_array() does not benefit from having a sorted array. PHP just walks along the whole array as if it were a linked list.

Categories