Prepend to array, but keep the indexes with PHP - 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

Related

Sorting objects in array

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);

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.

Function is changing array from numeric to associative

This is supposed to take any rows where ing_name is duplicated, combine the eff_name fields and delete the duplicate but it also has the side effect of changing the array from numeric to associative. My ajax is expecting numeric array.
for($i=count($recipe)-1; $i>0; $i--) {
if($recipe[$i]['ing_name'] == $recipe[$i-1]['ing_name']) { //check for duplicate. **array must be sorted by ing_name**
$recipe[$i-1]['eff_name'] .= ', '.$recipe[$i]['eff_name']; //Combine eff_name of duplicates
$recipe[$i-1]['link'] = true;
unset($recipe[$i]); //remove duplicate index
}
}
examples: NUM, ASSOC
Source
EDIT: So i figured it must have something to do with unsetting the index so I did this and it seems to work ok:
$newRecipe = array();
foreach($recipe as $r) {
$newRecipe[] = $r;
}
New question, is there a better way?
unset works with named keys. You could use array_splice instead, or get a brand new array after the loop with array_values (but that would be ugly!).
array_values() Will return a numerically indexed array

Help with getting first value of array in PHP

Stumped by this one:
I have a function that returns an array of folders in a given directory. When I iterate through the array, I can see all the items. However, if I try to print the first item, I get nothing:
function get_folders($dir) {
return array_filter(scandir($dir), function ($item) use ($dir) {
return (is_dir($dir.'/'.$item) && $item != "." && $item != "..") ;
});
}
$folders = get_folders(".");
$first_folder = $folders[0];
echo $first_folder; // returns blank.
Interestingly, if I don't filter out the "." and "..", then $first_folder does print ".". Can anyone explain this?
As noted in the manual: Array keys are preserved when using array_filter().
The keys are preserved from the call to scandir() which will include the . and .. directories, meaning your filtered array will start at 2 or more (whatever the key is for the first directory).
A simple fix would be to wrap the whole thing in array_values() to get the resultant array having keys starting from 0 and incrementing by one.
return array_values(array_filter(...));
If you don't actually care about the keys, then basic array functions could be of use like key or current.
From the array_filter manual:
Iterates over each value in the input array passing them to the callback function. If the callback function returns true, the current value from input is returned into the result array. Array keys are preserved.
So, scandir($dir) gets you an array with . at key 0, thus if you later filter . out, there will be nothing at key 0 in the result.
If you want to know what the first key of the resulting array is, try the array_keys function.
EDIT: actually, salathe's suggestion to use array_values is better in your case than getting the keys from array_keys.
can you print the folders and see if there is some key you can get the first folder with as opposed to selecting the index of zero? It seems lke $folders[0] would work unless the entries are stored with a different set of indexes / keys.
Try doing a
print_r($folders)
to see if it outputs your first folder and all other folders as expected with the corresponding indexes you're looking for.
array_filter preserves array keys, so if the first two elements have been removed, then the "new first" element has an index of 2. To convert that into an array indexed starting from 0, use array_values:
return array_values(array_filter(scandir($dir), function ($item) use ($dir) {
...
As others have said, array_filter preserves the keys in the array. Given that initially the item '.' has key 0, the filtered array ends up not having any item with key 0 (you can verify this with print_r($folders). So this line:
$first_folder = $folders[0];
ends up generating an E_NOTICE saying that there is no key 0 in the array (having notices turned on would alert you to the cause of the problem immediately, I highly recommend it) and giving $first_folder the value null.
To get the first value of the filtered array, regardless of key, use reset:
$first_folder = reset($folders);
if($first_folder === false) {
echo 'No folders!';
}
else {
echo 'First folder: '.$first_folder;
}

php array count max value

If I have:
$mainarray = some array of things with some repeated values
$array_counted = array_count_values ($mainarray);
How can I find the maximum value in $array_counted?
(This would be the element that appeared most often in $mainarray I think. Its mostly a syntax issue as I am pretty sure I could loop it, but not sure of the syntax to use)
You can find first max value as
$main_array = array(1,2,3,4,5,6,6,6,6,6,6,6);
$max_val = max($main_array);
for find all of max vals
in php < 5.3
function findmax($val)
{
global $max_val;
return $val == $max_val;
}
$max_values_array = array_filter($main_array,'findmax');
in php >= 5.3
$max_values_array = array_filter($main_array,function($val) use ($max_val) { return $val == $max_val; });
echo count($max_values_array);
var_dump($max_values_array);
You could sort the array and take the first, respectively last item out of it, if you don't want to loop.
Since you associate the count with the values with that:
$array_counted = array_count_values ($mainarray);
You only need to sort it afterwards, and return the first key (which is the most occured element):
arsort($array_counted);
print key($array_counted); // returns first key
ok, the guy whos answer I used has deleted his comment so here is how I did it:
I used arsort($array_counted) to sort the array, while keeping index. rsort alone does not work as the result of array_count_values is an associative array. Thank you all.

Categories