sorting arrays - Sorting an array from outside data - php

I am attempting to make an ordered array based on an unsorted array from an SQL database.
The data that is gotten from the database will look something like this:
Array (
//array ('name', position)
array ('george', 2),
array ('lenny' , 4),
array ('rabbit', 1),
array ('pet' , 3)
)
The idea is to sort the 'names' in an array where position is there place in the array.
What I would like to to end up being:
Array ( 'rabbit', 'george', 'pet', 'lenny' )
The current way I have attempted this is using split_array()
$result is the array from the database.
foreach ( $result as $res ){
$a = array(array($res['name'], $res['position']));
array_splice($finalArray, ($res['position'] - 1), 0, $a);
}
The issue is sometimes depending on the order the users are retrieved it will not sort it properly, is there a better way to do this, or is this good and I am doing it wrong?
Thanks.

Use uasort http://php.net/manual/en/function.uasort.php function where you can pass a user defined comparasion function like this:
$myArray = array(array('bill',3),array('joe',4),array('john',1));
/**
* #desc compare two arrays by the second element
* #param array $a (array to compare with an other)
* #param array $b (array to compare with an other)
* #return int 0|1|-1 equals|first is bigger|second is bigger
*/
function myCompare($a,$b){
if( $a[1] == $b[1] ){
return 0; //if the 2nd elements equals return 0
}
return ( $a[1] > $b[1] )?1:-1; //if the 2nd element of the 1st parameters is bigger returns 1 , else returns -1
}
Usage:
uasort( $myArray, 'myCompare' );
The uasort manipolates the original array in place.
Result:
var_dump($myArray);
array(
array('john',1),
array('bill',3),
array('joe',4)
);
Recommendation:
If you could edit the SQL query , better to short the results in the query with ORDER BY directive like this:
SELECT `name`,`position`
FROM `mytable` #your table name
WHERE 1 #or your conditions here
ORDER BY `position` ASC #ordering directive
This should run faster. And if use this, recommend to add index to position field.

Related

sort array based on other array sort

I have an array as follows:
$aq=['jonathan','paul','andy','rachel'];
Then I have an array as follows:
$bq=['rachel','andy','jonathan'];
What I need is to use the ordering of the first array to sort my second array.
So for this instance, the resulting sorted array should be:
$cq=['jonathan','andy','rachel'];
I started working on a solution that uses the highest key as the top value (the head of the array) because what Im looking for is the top value but that ran into issues and seemed more like a hack so i think sorting is what im looking for.
Is there a simple function in php that can sort my data based on my first array and there respective positions in the array
please try this short and clean solution using array_intersect:
$aq = ['jonathan','paul','andy','rachel'];
$bq = ['rachel','andy','jonathan'];
$cq = array_intersect($aq, $bq);
var_export($cq);
the output will be :
array ( 0 => 'jonathan', 2 => 'andy', 3 => 'rachel', )
You'll have to use a custom sort function. Here we grab the keys of corresponding entries in the "ordering" array and use them to order the working array.
In this example, we give up (return 0) if the key doesn't exist in the ordering array; you may wish to customize that behavior, but this should give you the general idea.
$order = ['jonathan','paul','andy','rachel'];
$arrayToSort =['rachel','andy','jonathan'];
usort($arrayToSort,function($a,$b) use ($order){
if( ! array_key_exists($a,$order) ) return 0;
if( ! array_key_exists($b,$order) ) return 0;
if( array_search($a,$order) > array_search($b,$order)
return 1;
return -1;
});

Check if item exists in multiple arrays

I have a function which returns an array:
This is the fucntion:
{
global $woocommerce;
$items = $woocommerce->cart->get_cart();
$product_names=array();
foreach($items as $item => $values) {
$_product = $values['data']->post;
$product_names[]=$_product->post_title;
}
$allproductname=print_r($product_names, true);
return $allproductname;
}
The output of this function:
Array(
[0] => Social media campagne
[1] => Marketingcampagne
)
I also have 2 arrays named group1 and group2.
$group1=array("Social media campagne","Marketingcampagne");
$group2=array("SEO","Facebook marketing");
Now what i want to check is if both of the values of the function output belong in $group1 then i want it to print "both values belong in group1"
And if 1 value belongs in group1 and one value in group 2 then echo "1 value belongs in group1 and one value belongs in group2"
--edit
I forgot to mention that this output can change its not always this:
Array(
[0] => Social media campagne
[1] => Marketingcampagne
)
it can also be 3 products for example
It looks like what you want to do relates to set theory. You have a set of things (the return from the function) and you want to see if all the elements in that array are in another array (You want to check if the return array is a strict subset of the array you're checking against).
You can use array_intersect () to do this. This function takes at least 2 arrays as its arguments, and it returns an array of elements that exist in all the arrays passed to it.
If you have an array specifying all the values you want to check against and another array that may or may not be a subset of that array then you can use array_intersect to get a list of all the elements in both arrays. If the number of elements in the output match the number of elements in the array that you want to check then the array must be a strict subset of the array you're checking against.
The following code demonstrates the basic principle:
$set = [1, 2, 3, 4, 5, 6, 7, 8]; // Data you want to test against
$subset = [2, 4, 6, 8]; // Strict subset of $set
$notSubset = [2, 4, 6, 10]; // Not a strict subset of $set because it contains 10
var_dump (count ($subset) === count (array_intersect ($set, $subset))); // true
var_dump (count ($notSubset) === count (array_intersect ($set, $notSubset))); // false
NOTE: array_intersect is only really suitable when the contents of the arrays being compared are all primitive types, as PHP will cast them all to string while comparing them. If you're comparing arrays of arrays or arrays of object then you're better off using array_uintersect () and specifying how the elements are compared yourself with a callback function.
To apply the array_intersect() from #GordonM to your problem (it seems like there are only strings in the arrays).
You first get the number of values from your output, that are in group1
$inGroup1 = array_intersect($ouput, $group1);
$inGroup1Count = count($inGroup1); // you can rewrite these two lines into one,
// if the actual matches are of no interest
If this is the same count as $output, than it's group1. If not, check how many are in group2. I guess you can code that yourself. And then check if inGroup1Count and inGroup2Count are both > 0. Than it's in both groups.
For logic reason you should also check if all are in group 2. Or is that impossible?
With checking both groups you can create an output like
echo $inGroup1Count.' value(s) belongs in group1 and '.$inGroup2Count.' value(s) belongs in group2';

How do array_udiff(), array_uintersect() etc. work?

There are a couple of similar questions here on SO, but I still haven't found an answer.
PHP manual states that
The comparison function must return an integer less than, equal to, or
greater than zero if the first argument is considered to be
respectively less than, equal to, or greater than the second.
The thing is that I don't understand why is it so important to have three optional outcomes, like -1, 0 and 1? Why wouldn't it work out if I used 0 for cases when two values being compared are equal and 1 otherwise?
A more practical question: I have a task where I should find elements of the first array that exist in the second one. The structures of the arrays are the same and look like the following:
Array
(
[0] => Array
(
[productId] => 5479046275
[options] => Array
(
[1] => All
[2] => Green
)
)
)
So I consider elements of such arrays equal when productId values match, and when there's no difference between options respecting their keys. Comparing options should be performed with the fact that 'All' options match every other's value. So I have a code like this:
$cartItems = <MyArray>;
$triggers = <MyAnotherArray>;
/**
* Options equal each other when they are exactly the same or
* when bundle offer's product has 'All' selected as option.
*/
$compareOptions = function ($a, $b) {
if ('All' == $b) {
return 0;
}
return strcmp($a, $b);
};
/**
* Compare product id to make sure these variants are of the same product
* Then check the options. If there's no difference, then variants
* are equal
*/
$compareVariants = function ($a, $b) use ($compareOptions) {
if ($a['productId'] != $b['productId']) {
return ($a['productId'] > $b['productId']) ? 1 : -1;
}
$optionsDiff = array_udiff_assoc($a['options'], $b['options'], $compareOptions);
if (0 === count($optionsDiff)) {
return 0;
} else {
return (count($optionsDiff) > 0) ? 1 : -1;
}
};
return array_uintersect($cartItems, $triggers, $compareVariants);
Then I xDebugged it. For some reason, when $optionsDiff is empty and script returns 0, it doesn't not step out of $compareVariants function, but goes to $compareOptions comparing arrays which produces a error.
Why does it work like that?
Thanks.
array_udiff_assoc() will compare the keys using built-in function and values will be compared using user-defined function.
array_udiff_assoc($array1,$array2,"userDefinedFunction");
So no matter what the result is. The user defined function will be called automatically to compare the array values. If you don't want to call your 'compareOptions' function, then you can go for array_diff_assoc($array1,$array2). This will use built in function to compare both keys and values of the arrays.

Randomize array of objects which contains specific key->value

I have an array with 45 object elements containing id, name, is_premium.
From MySQL I receive them, ordered by is_premium desc, and some of them have is_premium = 0 at the end of list.
How can I randomize elements with is_premium=1, keeping the is_premium=0 at the end of array?
Try if this works:
<?php
//assuming the array of objects is called $array
$new_array = array_merge(
shuffle(
array_filter($array,function($x){return $x['is_premium'] == 1;})
),
array_filter($array,function($x){return $x['is_premium'] == 0;})
);
?>

Fast method for Looping through Array to match a common ID in a second array

I'm trying to systematically loop through 2 arrays, and match their values for some quick processing. Let me set up my specific situation:
Array 1
productID,
companyID,
name,
price
Array 2
companyID,
name,
rebate1,
rebate2
I want to loop through Array 1, and when the companyID matches an ID inside of Array 2, I will do some quick math based on the rebate1, rebate2 values for that companyID.
Right now I am looping through Array 1, and then on EACH item in Array 1 I loop through the entire Array 2 to see if the companyID exists. I know this can't be the fastest/cleanest solution...
EDIT
The key values for Array 1 look like:
$array1[0]['productID']
$array1[0]['companyID'] (etc...)
$array1[1]['productID']
$array1[1]['companyID'] (etc...)
The key values for Array 2 look like:
$array2[0]['companyID']
$array2[0]['rebate1'] (etc...)
$array2[1]['companyID']
$array2[1]['rebate1'] (etc...)
Use the companyId as key for Array 2, i.e., make sure that
$Array2[$Array1[$i]['companyID']]['companyID'] == $Array1[$i]['companyID']
This gives you constant time lookup of companies in Array 2 based on companyID and you can do your calculation with
$Array2[$Array1[$i]['companyID']]['rebate1']`
and
$Array2[$Array1[$i]['companyID']]['rebate2']`
Example:
foreach ($Array1 as $value) {
if (isset($Array2[$value['companyID']])) {
//TODO: use $Array2[$value['companyID']] for calculation
} else {
// TODO: handle case companyID not in $Array2
}
}
What approximate sizes do you expect for each of your arrays?
While as you say, your method isn't certainly the fastest (looks like 0(n²)), below 10'000 elements in each array I doubt you can see any significant speed difference.
If you have 150'000 in array1 and 200'000 in array2, that's a whole other story and you'll have to look for an algorithm that is rather 0(log n).
Edit:
As mentioned above, let's just make your array associative if you can:
Instead of:
Array2 = array(
0 => array(
'Company_id' => 'Hello',
'rebate_1' => '50%',
)
);
Make it:
Array2 = array(
'Hello' => array(
'rebate_1' => '50%',
)
);
And then use:
if (isset(array2[$company_id]))
{
// do your stuff
}
If you can't modify Array2's structure where it's coming from, you should transform it on the fly in your search function's scope, so that it looks like above, and then use the transformed array. Transforming Array2 into an associative one shouldn't take too long, for the number of elements you say you have.
The easiest way I can think of is to use the companyID as the key for Array 2:
$companies[$companyID]=array($name,$rebate1,$rebate2)
and then you just reference it directly looping Array 1
$products[$x]=array($productID,$companyID,$name,$price);
...
$newprice1=$products[$x][3]/$companies[$products[$x][1]][1];
$newprice2=$products[$x][3]/$companies[$products[$x][1]][2];
My answer is slightly different from the first one, mind the arrays...
You can create a new array indexed by the company id as follows:
$cid = array_map(function($a) {return $a['companyID'];}, $array2);
$new2 = array_combine($cid, $array2);
With that, you can loop through the first array and access the data:
foreach ($array1 as $key => $value){
$rebate1 = $new2[$value['companyID']]['rebate1'];
$rebate2 = $new2[$value['companyID']]['rebate2'];
}

Categories