PHP calculating the intersect of arrays - php

Array declaration: $uids = array();
Next these arrays may or may not be created:
$uids['locations'];
$uids['ages'];
$uids['genders'];
If at least 2 of them are created I want to calculate the intersect. If all 3 are created I want the intersect of all 3.
So, I may want to calculate the intersect of $uids['locations'] and $uids['ages'] or the intersect of $uids['ages'] and $uids['genders'], etc.
If put all 3 arrays in array_intersect then I get errors if one of them is not an array. I'm not sure how to handle this without an awful lot of if:else statements and think there is a better way.

If you know that you don't have more array keys than the ones specified, you can use this:
$intersect = array();
if (count($uids) > 1) {
$intersect = call_user_func_array('array_intersect', $uids);
}
Otherwise you could try this one:
$_uids = array_intersect_key($uids, array(
'locations' => 1,
'ages' => 1,
'genders' => 1,
));
if (count($uids) > 1) {
$intersect = call_user_func_array('array_intersect', $_uids);
}

Related

return an array of numbers that show up in all three sub arrays

I want to compare all the sub arrays in the $ids and I want to return only the numbers that show up in all three arrays, so it would return 3 and 4 as an array.
$ids = [
[1,2,3,4],
[2,3,4],
[3,4,5],
];
expecting it to return
array(3,4)
UPDATE: My apologies, I left out the detail that I would not know how many arrays would be in the associative array, it could be 2 sub arrays, other times it could be 5. I appreciate all the answers I have received.
Obviously array_intersect is the solution How to get common values from two different arrays in PHP. If you know the number of sub-arrays and their indexes then it's as simple as:
$result = array_intersect($ids[0], $ids[1], $ids[2]);
However, if you need to do it for an unknown/variable number of sub-arrays and/or unknown indexes, use $ids as an array of arguments with call_user_func_array:
$result = call_user_func_array('array_intersect', $ids);
Or better use Argument unpacking via ... (PHP >= 5.6.0):
$result = array_intersect(...$ids);
Splice out the first subarray and then loop the rest and use array_intersect to filter the result to 3,4.
$res = array_splice($ids,0,1)[0];
foreach($ids as $id){
$res = array_intersect($res, $id);
}
var_dump($res); // 3,4
https://3v4l.org/Z7uZK

How can the elements of a PHP array with matching characteristics be processed into a series of aggregates?

Essentially I want to perform a kind of grouping against a PHP array, and then squash the elements in each group into a single aggregate value.
Specifically, I have a PHP array with the following form:
[
[date, int],
[date, int],
[date, int],
...
[date, int]
]
and I want to process this so that I end up with an array of arrays each containing a unique date and the sum of the ints that went with that date in the original array, e.g.:
[
['2017-01-01', 1],
['2017-01-01', 1],
['2018-01-01', 1],
['2019-01-01', 1],
['2019-01-01', -1],
['2020-01-01', -1],
['2020-01-01', 1],
['2020-01-01', -1]
]
should result in this:
[
['2017-01-01', 2],
['2018-01-01', 1],
['2019-01-01', 0],
['2020-01-01', -1]
]
The original array is in date order.
What's an efficient way of achieving this?
I would do it like this, assuming your input is in $arr:
foreach ($arr as list($date, $num)) {
$result[$date] = isset($result[$date]) ? $result[$date]+$num : $num;
}
Now $result will be almost as you asked for. It will in fact produce key/value pairs, where the key is the date, and the value the number. If you really prefer the nested array format, then:
foreach ($arr as list($date, $num)) {
if (!isset($result[$date])) $result[$date] = [$date, 0];
$result[$date][1] += $num;
}
This will still have the dates as keys, but they will have the pairs as values.
If you want a sequential array instead of dates as keys, then add:
$result = array_values($result);
Perhaps something like this (assuming your array of arrays above is called $source):
$destination = array();
foreach ( $source as $date_value ) {
if ( isset( $destination[ $date_value[0] )) {
$destination[ $date_value[0] ] += $date_value[1];
} else {
$destination[ $date_value[0] ] = $date_value[1];
}
}
This will create an array with the dates as keys and the sums as the values of those keys. Not specifically what you were asking for. To format it otherwise:
$new_destination = array();
foreach ( $destination as $key => value ) {
$new_destination[] = array( $key, $value );
}
Now $new_destination should be an array that matches your desired output. This can be done when creating the first array, but will get very messy. So even though it creates two loops, it prevents the need for nested loops, and is likely more efficient than doing it in one block.
Note that I haven't tested this, so it may contain syntax errors or need to be modified slightly to get what you need, but it should put you on the right track.

Using php array_multisort twice to sort the same array

I have a large multidimensional array and I want to sort it twice by date using array_multisort and get the last 3 arrays from each sort
I could create a duplicate of the array but it seems a waste when all I want is 3 arrays from it
$rows = array(
array(...),
array(...),
...
);
I create the arrays to be sorted like this
foreach($rows as $key => $row) {
$submit_date[$key] = $row['Submit_Date'];
$view_date[$key] = $row['View_Date'];
}
On this iteration of the sort, everything works as I expect
array_multisort($view_date, SORT_DESC, $rows);
$viewed = array_slice(array_unique($rows, SORT_REGULAR), 0, 3, true);
but on this one which is run straight after, I get different results to what I expect
array_multisort($submit_date, SORT_DESC, $rows);
$unlisted = array_slice(array_unique($rows, SORT_REGULAR), 0, 3, true);
I can't sort on both sort arrays because there will be occasions where $view_date array will have null values.
Is there a way I can use the same array to sort by view date, get the last 3 rows then sort the array by submit date then get the last 3 rows?
It's because your first multisort messed up the order of $rows.
A dummy array should do the trick: $temp = $rows;

Looking up keys for a multi-dimensional array

I have an array with a key and 3 values (day, start_time, end_time). I want to keep adding certain entries into this array while making sure each entry is unique. That means that every time I try to add an item into the array, I want to make sure it does not already exist in it. If it does exist, I want to be able to find the key that indicates that entry.
For example, this is the pre-existing array:
$array [0][0] = Monday
$array [0][1] = 2
$array [0][2] = 4
$array [1][0] = Tuesday
$array [1][1] = 3
$array [1][2] = 5
If I try to insert (Wednesday, 3, 5), then it should make the entry in the index 2.
If I try to insert (Monday, 2, 4), I need to be able to know that it is already in there and is indexed by 0.
How do I go about doing this?
I agree with the other answers here — it might be better to restructure your array so that there is no need to worry about duplication at all.
If you want to keep your current structure, however: use array_search.
$array = ...
$unique_check = array_search(array('Monday', 2, 4), $array);
if ( $unique_check === false )
// add to array
else
// $unique_check = the array key at which the existing matching element is located
Why not organize the array this way?
$array [Monday][0] = 2
$array [Monday][1] = 4
$array [Tuesday][0] = 3
$array [Tuesday][1] = 5

Using PHP remove duplicates from an array without using any in- built functions?

Lets say I have an array as follows :
$sampArray = array (1,4,2,1,6,4,9,7,2,9)
I want to remove all the duplicates from this array, so the result should be as follows:
$resultArray = array(1,4,2,6,9,7)
But here is the catch!!! I don't want to use any PHP in built functions like array_unique().
How would you do it ? :)
Here is a simple O(n)-time solution:
$uniqueme = array();
foreach ($array as $key => $value) {
$uniqueme[$value] = $key;
}
$final = array();
foreach ($uniqueme as $key => $value) {
$final[] = $key;
}
You cannot have duplicate keys, and this will retain the order.
A serious (working) answer:
$inputArray = array(1, 4, 2, 1, 6, 4, 9, 7, 2, 9);
$outputArray = array();
foreach($inputArray as $inputArrayItem) {
foreach($outputArray as $outputArrayItem) {
if($inputArrayItem == $outputArrayItem) {
continue 2;
}
}
$outputArray[] = $inputArrayItem;
}
print_r($outputArray);
This depends on the operations you have available.
If all you have to detect duplicates is a function that takes two elements and tells if they are equal (one example will be the == operation in PHP), then you must compare every new element with all the non-duplicates you have found before. The solution will be quadratic, in the worst case (there are no duplicates), you need to do (1/2)(n*(n+1)) comparisons.
If your arrays can have any kind of value, this is more or less the only solution available (see below).
If you have a total order for your values, you can sort the array (n*log(n)) and then eliminate consecutive duplicates (linear). Note that you cannot use the <, >, etc. operators from PHP, they do not introduce a total order. Unfortunately, array_unique does this, and it can fail because of that.
If you have a hash function that you can apply to your values, than you can do it in average linear time with a hash table (which is the data structure behind an array). See
tandu's answer.
Edit2: The versions below use a hashmap to determine if a value already exists. In case this is not possible, here is another variant that safely works with all PHP values and does a strict comparison (Demo):
$array = array (1,4,2,1,6,4,9,7,2,9);
$unique = function($a)
{
$u = array();
foreach($a as $v)
{
foreach($u as $vu)
if ($vu===$v) continue 2
;
$u[] = $v;
}
return $u;
};
var_dump($unique($array)); # array(1,4,2,6,9,7)
Edit: Same version as below, but w/o build in functions, only language constructs (Demo):
$array = array (1,4,2,1,6,4,9,7,2,9);
$unique = array();
foreach($array as $v)
isset($k[$v]) || ($k[$v]=1) && $unique[] = $v;
var_dump($unique); # array(1,4,2,6,9,7)
And in case you don't want to have the temporary arrays spread around, here is a variant with an anonymous function:
$array = array (1,4,2,1,6,4,9,7,2,9);
$unique = function($a) /* similar as above but more expressive ... ... you have been warned: */ {for($v=reset($a);$v&&(isset($k[$v])||($k[$v]=1)&&$u[]=$v);$v=next($a));return$u;};
var_dump($unique($array)); # array(1,4,2,6,9,7)
First was reading that you don't want to use array_unique or similar functions (array_intersect etc.), so this was just a start, maybe it's still of som use:
You can use array_flip PHP Manual in combination with array_keys PHP Manual for your array of integers (Demo):
$array = array (1,4,2,1,6,4,9,7,2,9);
$array = array_keys(array_flip($array));
var_dump($array); # array(1,4,2,6,9,7)
As keys can only exist once in a PHP array and array_flip retains the order, you will get your result. As those are build in functions it's pretty fast and there is not much to iterate over to get the job done.
<?php
$inputArray = array(1, 4, 2, 1, 6, 4, 9, 7, 2, 9);
$outputArray = array();
foreach ($inputArray as $val){
if(!in_array($val,$outputArray)){
$outputArray[] = $val;
}
}
print_r($outputArray);
You could use an intermediate array into which you add each item in turn. prior to adding the item you could check if it already exists by looping through the new array.

Categories