Array Intersect giving wrong output - php

I need to find common elements between two arrays. My code is:
$sql="SELECT DISTINCT fk_paytbl_discounts_discountid as discountid from paytbl_discounts_students WHERE fk_vtiger_cf_601='".$categoryid."'";
$discountstudentinfo=$objdb->customQuery($sql,false);
$sql1="SELECT DISTINCT fk_paytbl_discounts_discountid as discountid from paytbl_discounts_variants WHERE fk_vtiger_products_productid='".$variantid."'";
$discountvariantinfo=$objdb->customQuery($sql1,false);
$commondiscount=array_intersect($discountvariantinfo,$discountstudentinfo);
First array
Array
(
[0] => Array
(
[discountid] => 2
)
[1] => Array
(
[discountid] => 8
)
[2] => Array
(
[discountid] => 5
)
[3] => Array
(
[discountid] => 4
)
)
Second array
Array
(
[0] => Array
(
[discountid] => 1
)
[1] => Array
(
[discountid] => 5
)
)
Common array
Array
(
[0] => Array
(
[discountid] => 1
)
[1] => Array
(
[discountid] => 5
)
)
Common array should have only discountid 5 but its showing 1 also.
Please help me on this
Thanks

http://php.net/array_intersect
Note: Two elements are considered
equal if and only if (string) $elem1
=== (string) $elem2. In words: when the string representation is the same.
So the reason you are experiencing a problem is because, for example:
(string) array('discountid' => 5) == (string) array('discountid' => 8)
If you are running PHP 5.3, this is one solution:
$comparisonFunction = function($elem1, $elem2) {
return $elem1['discountid'] == $elem2['discountid'];
}
$commondiscount = array_uintersect(
$discountvariantinfo,
$discountstudentinfo,
$comparisonFunction
);
Prior to PHP 5.3 you could use the uglier create_function() instead of the nifty closure. If your executing inside a method it would likely be easy to tack on a new private method to use as a callback.
If you are not using PHP 5.3 and you really don't want to use a callback, you could use the following idea:
$uniqueDiscounts = array();
foreach ($discountvariantinfo as $dvi) {
$uniqueDiscounts[$dvi['discountid']] += 1;
}
foreach ($discountstudentinfo as $dsi) {
$uniqueDiscounts[$dsi['discountid']] += 1;
}
$commondiscount = array();
foreach ($uniqueDiscounts as $ud => $count) {
if ($count == 2) {
$commondiscount[] = array('discountid' => $ud);
}
}
You will, of course, want to tidy this up or add comments to explain the algorithm.

Related

merging array in CI 3

I want to merge two arrays in order to get the data as per my requirement.
I am posting my result, please have a look.
First array:
Array
(
[0] => Array
(
[km_range] => 300
[id] => 2
[car_id] => 14782
)
[1] => Array
(
[km_range] => 100
[id] => 3
[car_id] => 14781
)
[2] => Array
(
[km_range] => 300
[id] => 4
[car_id] => 14783
)
)
Second array:
Array
(
[0] => Array
(
[user_id] => 9c2e00508cb28eeb1023ef774b122e86
[car_id] => 14783
[status] => favourite
)
)
I want to merge the second array into the first one, where the value at key car_id matches the equivalent value; otherwise it will return that field as null.
Required output:
<pre>Array
(
[0] => Array
(
[km_range] => 300
[id] => 2
[car_id] => 14782
)
[1] => Array
(
[km_range] => 100
[id] => 3
[car_id] => 14781
)
[2] => Array
(
[km_range] => 300
[id] => 4
[car_id] => 14783
[fav_status] => favourite
)
)
Since the merge is so specific I would try something like this:
foreach ($array1 as $index => $a1):
foreach ($array2 as $a2):
if ($a1['car_id'] == $a2['car_id']):
if ($a2['status'] == "favourite"):
$array1[$index]['fav_status'] = "favourite";
endif;
endif;
endforeach;
endforeach;
You might be able to optimize the code more but this should be very easy to follow...
Another way to achieve this without using the index syntax is to reference the array elements in the foreach by-reference by prepending the ampersand operator:
foreach($firstArray as &$nestedArray1) {
foreach($secondArray as $nestedArray2) {
if ($nestedArray1['car_id'] == $nestedArray2['car_id']) {
$nestedArray1['fav_status'] = $nestedArray2['status'];
}
}
}
You can see it in action in this Playground example.
Technically you asked about merging the arrays. While the keys would be different between the input arrays and the desired output (i.e. "status" vs "fav_status"), array_merge() can be used to merge the arrays.
if ($nestedArray1['car_id'] == $nestedArray2['car_id']) {
$nestedArray1 = array_merge($nestedArray1, $nestedArray2);
}
Playground example.
Additionally the union operators (i.e. +, +=) can be used.
If you want to append array elements from the second array to the first array while not overwriting the elements from the first array and not re-indexing, use the + array union operator1
if ($nestedArray1['car_id'] == $nestedArray2['car_id']) {
$nestedArray1 += nestedArray1;
}
Playground example.
1http://php.net/manual/en/function.array-merge.php#example-5587

PHP Sort Multidimensional Array By Number Of Entries - If Equal Alphabetical

I have a multidimensional array, and I am trying to sort it so that the array with the most entries comes first, etc... Then if two arrays have the same number of entries, they should be arranged alphabetically. Also, if the entries could be sorted by the key, 'name', I think that would be great. As you can see below, I am using ldap_sort to sort by 'name'. But I'm sure calling too many sort functions is bad practice.
if ($conn == True ) {
Try {
// Authenticate
$bind = ldap_bind($conn, $user, $pass);
// Search AD
$search = ldap_search($conn, $dn, $filter, $attr);
// Sort
ldap_sort($conn, $search, 'name');
// Retrieve Data
$records = ldap_get_entries($conn, $search);
Foreach ($records as $record) {
if(is_array($record) && array_key_exists('l', $record)) {
$locations[$record['l'][0]][] = $record;
}
continue;
}
} finally {
// Close Connection
ldap_close($conn);
}
} else {
trigger_error('Unable_To_Connect_To_Server');
}
// Sort Location By Number Of Entries
array_multisort(array_map('count', $locations), SORT_DESC, $locations);
I guess to put it layman's terms.. Sorting entries alphabetically by their 'name' value, should be inherent. Then the arrays should be sorted by the number of entries, and if any arrays have the same number of entries they should be sorted alphabetically.
P.S. - I'm asking for help because it's hard for me to understand multidimensional arrays (especially those returned by ldap_search) and sorting them is even more mind-boggling to me.
EDIT Like I said, arrays confuse me but hopefully the below accurately depicts my intentions:
Array (
[Location1] => Array (
[0] => Array (
[l] => Array (
[count] => 1
[0] => Location1
)
[0] => l
[telephonenumber] => Array (
[count] => 1
[0] => XXX.XXX.XXXX
)
[1] => telephonenumber
[department] => Array (
[count] => 1
[0] => Department1
)
[2] => department
[name] => Array (
[count] => 1 [0] => User1
)
[3] => name
[ipphone] => Array (
[count] => 1
[0] => IPPhone1
)
[4] => ipphone
[mail] => Array (
[count] => 1
[0] => user#domain.com
)
[5] => mail
[count] => 6
[dn] => DistinguishedName1
)
)
)
I cut the above short (there are hundreds of records returned) and I'm not sure I ended it correctly. But I am essentially parsing the information to output something like below.
c_Location1
a_user1
b_user1
c_user1
a_Location2
a_user2
b_user2
b_location3
a_user3
b_user3
Write a function that compares the lengths of the arrays. If they're the same, it compares the name entries. Use that as the callback function for usort.
usort($records, function($x, $y) {
if (count($x) == count($y)) {
$u1 = $x['name'][0];
$u2 = $y['name'][0];
return $u1 < $u2 ? -1 :
($u1 > $u2 ? 1 : 0);
} else {
return count($y) - count($x);
}
});

Passing multiple arrays to a Cartesian function

I need to pass multiple array's in an indexed format to a cartesain function in order to calculate every permutation. This works when the code is:
$count = cartesian(
Array("GH20"),
Array(1,3),
Array(6,7,8),
Array(9,10)
);
I will not always know the length, number of arrays, or values so they are stored in another array "$total" which may look something like this:
Array (
[0] => Array
(
[0] => 1
[1] => 3
)
[1] => Array
(
[0] => 6
[1] => 7
[2] => 8
)
[2] => Array
(
[0] => 9
[1] => 10
)
)
I have tried implementing the user_call_back_function as per:
$count = call_user_func('cartesian', array($total));
However the array that then gets passed looks like this:
Array (
[0] => Array (
[0] => Array (
[0] => Array (
[0] => 1
[1] => 3
[2] => 4
)
[1] => Array (
[0] => 5
[1] => 6
[2] => 7
[3] => 8
)
[2] => Array (
[0] => 9
[1] => 10
)
)
)
)
Where am I going wrong, why is the array being buried further down in dimensions where it is not needed, and is this the reason why my cartesain function does no longer work?
Thanks, Nick
As requested, here is my cartesain function:
function cartesian() {
$_ = func_get_args();
if(count($_) == 0)
return array(array());
$a = array_shift($_);
$c = call_user_func_array(__FUNCTION__, $_);
$r = array();
foreach($a as $v)
foreach($c as $p)
$r[] = array_merge(array($v), $p);
return $r;
}
why is the array being buried further down in dimensions where it is not needed?
Simply because you are wrapping an array in another array when calling call_user_func.
$count = call_user_func('cartesian', array($total));
Perhaps you meant this:
$count = call_user_func('cartesian', $total);
is this the reason why my cartesain function does no longer work?
I don't know, you have not posted your cartesain, just an arrat called cartesain
EDIT as op updated the question.
If you are using PHP 5.6 you should be able to use the splat operator.
call_user_func("cartesain", ...$total);
Disclaimer, I have not tested this.
Arrays and Traversable objects can be unpacked into argument lists when calling functions by using the ... operator.

Optimum algorithm to generate keys based on permutations

In my application , I have few parameters (zone_id, startdate, enddate, brand, model) which I get from my UI form . Each of these parameters is an array containing 1 or more parameters .
My form parameters looks something like this :
Array
(
[sel_date_option] => today
[startdate] => 2011-09-19
[enddate] => 2011-09-19
[zone_id] => 1576,1562,1561
[model] => Array
(
[0] => A300
)
[brand] => Array
(
[0] => ACTS
)
)
Now , I want to generate keys which are combinations of these parameters . They would be something like :
[zone_id]_[model]_[brand]_[model]_[startdate]_[enddate]
This reflect all the possible arrangements of the above values .
For the above inputs, I should get the following keys :
1576_ACTS_A300_2011-09-19
1562_ACTS_A300_2011-09-19
1561_ACTS_A300_2011-09-19
Inside of giving the same startdate and enddate once can also enter a period like from 2011-09-19 to 2011-09-21.
What I am doing is I am using nested looping through all the parameter array and then creating a complex array of arrays something like the following :
Array
(
[0] => Array
(
[0] => 1576_DZ_A300
)
[1] => Array
(
[0] => 1576_DZ_A300
[1] => 1562_DZ_A300
)
[2] => Array
(
[0] => 1576_DZ_A300
[1] => 1562_DZ_A300
[2] => 1561_DZ_A300
)
[3] => Array
(
[0] => 1576_DZ_A300
[1] => 1562_DZ_A300
[2] => 1561_DZ_A300
[3] => 1563_DZ_A300
)
)
What I am doing is first I creating an array of all zones as :
Array
(
[0] => 1576
[1] => 1562
[2] => 1561
[3] => 1563
)
Then I am looping it using a nested loop for all the possible models and brands array like this :
function getInventoryData($criteria)
{
$index = "";
if($criteria['zone_id']!='')
{
$zone = explode(',', $criteria['zone_id']);
for($i=0;$i<count($zone);$i++)
{
$index[] .= $zone[$i];
}
echo '<pre>';print_r($index);exit;
}
if(!empty($criteria['model']))
{
foreach($index as $key=>$value)
{
foreach($criteria['model'] as $model)
{
$temparr[] = $index[$key].'_'.$model;
}
$index[$key] = $temparr;
}
}
Now , is there any other efficient method to achieve this ?
Moreover , there is another overhead associated with the above method :
While reading the generated keys , I have to loop through all the levels and in case of large sequence of data , the complexity can be really a matter of concern.
If I understand what you are trying to do correctly, this the most efficient method I can come up with for doing the above:
function getInventoryData ($arr) {
// Make sure all required keys are set
if (!isset($arr['zone_id'],$arr['model'],$arr['brand'],$arr['startdate'],$arr['enddate'])) return FALSE;
// Make a date string for the end of the keys
$dateStr = $arr['startdate'].(($arr['startdate'] == $arr['enddate']) ? '' : '_'.$arr['enddate']);
// Normalise the data
if (!count($arr['zone_id'] = array_unique(explode(',',$arr['zone_id']))) || !count($arr['brand'] = array_unique($arr['brand'])) || !count($arr['model'] = array_unique($arr['model']))) return FALSE;
// Get all possible permutations
$result = array();
foreach ($arr['zone_id'] as $zone) foreach ($arr['brand'] as $brand) foreach ($arr['model'] as $model) $result[] = "{$zone}_{$brand}_{$model}_{$dateStr}";
// Return the result
return $result;
}

calculations between two Multidimensional arrays

I have this code:
$id = new matrix(array(0=>array(1,0.5,3), 1=>array(2,1,4), 2=>array(1/3,1/4,1)));
$soma = $id->times($id)->sumRows();
That outputs this:
matrix Object ( [numbers] => Array ( [0] => Array ( [0] => 12.75 [1] => 22.3333333333 [2] => 4.83333333333 ) ) [numColumns] => 3 [numRows] => 1 )
and:
$total = $id->times($id)->sumRows()->sumTotal($id);
That outputs this:
matrix Object ( [numbers] => Array ( [0] => Array ( [0] => 39.9166666667 ) ) [numColumns] => 3 [numRows] => 1 )
Now, i am trying to make:
foreach ($soma as $value){
$final = (int)$value/(int)$total;
print_r ((int)$final);
}
The output will be 000.
Must be:
12.75/39.9166666667 = 0,3269230769230769
22.3333333333 / 39.9166666667 = ...
and so on
Thanks!
Just some ideas, without really knowing much about the matrix class...
All those (int)s should probably be (float)s, as you seem to want a non-int answer.
$value is itself an object, so you'll probably need to use $value['numbers'][0][0 or 1 or 2]. Same goes for $total.
the issue is solved :
documentation:
get_data($..)

Categories