Array permutations in multidimensional array keeping the keys PHP - php

For two days I've been running crazy trying to accomplish this, maybe you can enlighten me. This is for a horse betting permutation. Every time a user plays, I get a multidimensional array (2 levels). The first level contains the race ID, the the second level contains thee horses selected by the user for that race. It looks like this:
$play = array
(
'4' => array(7, 32),
'8' => array(4),
'2' => array(9),
'12' => array('5'),
'83' => array('10', '11', '12', ''),
'9' => array('3'),
);
I need to know what are all the possible combinations for that play. Which is easily done with this function:
function permutations(array $array)
{
switch (count($array)) {
case 1:
return $array[0];
break;
case 0:
throw new InvalidArgumentException('Requires at least one array');
break;
}
$a = array_shift($array);
$b = permutations($array);
$return = array();
foreach ($a as $key => $v) {
if(is_numeric($v))
{
foreach ($b as $key2 => $v2) {
$return[] = array_merge(array($v), (array) $v2);
}
}
}
return $return;
}
This returns an array with all the possible combinations beautifully. So far so good, and the result looks like this:
Array
(
[0] => Array
(
[0] => 7
[1] => 4
[2] => 9
[3] => 5
[4] => 10
[5] => 3
)
[1] => Array
(
[0] => 7
[1] => 4
[2] => 9
[3] => 5
[4] => 11
[5] => 3
)
[2] => Array
(
[0] => 7
[1] => 4
[2] => 9
[3] => 5
[4] => 12
[5] => 3
)
[3] => Array
(
[0] => 32
[1] => 4
[2] => 9
[3] => 5
[4] => 10
[5] => 3
)
[4] => Array
(
[0] => 32
[1] => 4
[2] => 9
[3] => 5
[4] => 11
[5] => 3
)
[5] => Array
(
[0] => 32
[1] => 4
[2] => 9
[3] => 5
[4] => 12
[5] => 3
)
)
My problem: I need the array "key" for every horse to be the "race ID", not 0,1,2,3. I need the result to be like this:
Array
(
[0] => Array
(
[4] => 7
[8] => 4
[2] => 9
[12] => 5
[83] => 10
[9] => 3
)
[1] => Array
(
[4] => 7
[8] => 4
[2] => 9
[12] => 5
[83] => 11
[9] => 3
)
[2] => Array
(
[4] => 7
[8] => 4
[2] => 9
[12] => 5
[83] => 12
[9] => 3
)
[3] => Array
(
[4] => 32
[8] => 4
[2] => 9
[12] => 5
[83] => 10
[9] => 3
)
[4] => Array
(
[4] => 32
[8] => 4
[2] => 9
[12] => 5
[83] => 11
[9] => 3
)
[5] => Array
(
[4] => 32
[8] => 4
[2] => 9
[12] => 5
[83] => 12
[9] => 3
)
)
How can I accomplish this? I know its a long post but I needed to graph this. I am having problems to wrap my head around the function recursion and I get totally lost in each loop.

I've got the same problem and Danny's solution wasn't good for me.
I manage thousand of permutation and store them in memory is damn expensive.
Here my solution:
/**
* Calculate permutation of multidimensional array. Without recursion!
* Ex.
* $array = array(
* key => array(value, value),
* key => array(value, value, value),
* key => array(value, value),
* );
*
* #copyright Copyright (c) 2011, Matteo Baggio
* #param array $anArray Multidimensional array
* #param function $isValidCallback User function called to verify the permutation. function($permutationIndex, $permutationArray)
* #return mixed Return valid permutation count in save memory configuration, otherwise it return an Array of all permutations
*/
function permutationOfMultidimensionalArray(array $anArray, $isValidCallback = false) {
// Quick exit
if (empty($anArray))
return 0;
// Amount of possible permutations: count(a[0]) * count(a[1]) * ... * count(a[N])
$permutationCount = 1;
// Store informations about every column of matrix: count and cumulativeCount
$matrixInfo = array();
$cumulativeCount = 1;
foreach($anArray as $aColumn) {
$columnCount = count($aColumn);
$permutationCount *= $columnCount;
// this save a lot of time!
$matrixInfo[] = array(
'count' => $columnCount,
'cumulativeCount' => $cumulativeCount
);
$cumulativeCount *= $columnCount;
}
// Save the array keys
$arrayKeys = array_keys($anArray);
// It needs numeric index to work
$matrix = array_values($anArray);
// Number of column
$columnCount = count($matrix);
// Number of valid permutation
$validPermutationCount = 0;
// Contain all permutations
$permutations = array();
// Iterate through all permutation numbers
for ($currentPermutation = 0; $currentPermutation < $permutationCount; $currentPermutation++) {
for ($currentColumnIndex = 0; $currentColumnIndex < $columnCount; $currentColumnIndex++) {
// Here the magic!
// I = int(P / (Count(c[K-1]) * ... * Count(c[0]))) % Count(c[K])
// where:
// I: the current column index
// P: the current permutation number
// c[]: array of the current column
// K: number of the current column
$index = intval($currentPermutation / $matrixInfo[$currentColumnIndex]['cumulativeCount']) % $matrixInfo[$currentColumnIndex]['count'];
// Save column into current permutation
$permutations[$currentPermutation][$currentColumnIndex] = $matrix[$currentColumnIndex][$index];
}
// Restore array keys
$permutations[$currentPermutation] = array_combine($arrayKeys, $permutations[$currentPermutation]);
// Callback validate
if ($isValidCallback !== false) {
if ($isValidCallback($currentPermutation, $permutations[$currentPermutation]))
$validPermutationCount++;
// *** Uncomment this lines if you want that this function return all
// permutations
//else
// unset($permutations[$currentPermutation]);
}
else {
$validPermutationCount++;
}
// Save memory!!
// Use $isValidCallback to check permutation, store into DB, etc..
// *** Comment this line if you want that function return all
// permutation. Memory warning!!
unset($permutations[$currentPermutation]);
}
if (!empty($permutations))
return $permutations;
else
return $validPermutationCount;
}
//
// How to?
//
$play = array(
'4' => array(7, 32),
'8' => array(4),
'2' => array(9),
'12' => array('5'),
'83' => array('10', '11', '12', ''), // <-- It accept all values, nested array too
'9' => array('3'),
);
$start = microtime(true);
// Anonymous function work with PHP 5.3.0
$validPermutationsCount = permutationOfMultidimensionalArray($play, function($permutationIndex, $permutationArray){
// Here you can validate the permutation, print it, etc...
// Using callback you can save memory and improve performance.
// You don't need to cicle over all permutation after generation.
printf('<p><strong>%d</strong>: %s</p>', $permutationIndex, implode(', ', $permutationArray));
return true; // in this case always true
});
$stop = microtime(true) - $start;
printf('<hr /><p><strong>Performance for %d permutations</strong><br />
Execution time: %f sec<br/>
Memory usage: %d Kb</p>',
$validPermutationsCount,
$stop,
memory_get_peak_usage(true) / 1024);
If someone has a better idea i'm here!

Here's what you need. I have commented as necessary:
function permutations(array $array)
{
switch (count($array)) {
case 1:
// Return the array as-is; returning the first item
// of the array was confusing and unnecessary
return $array;
break;
case 0:
throw new InvalidArgumentException('Requires at least one array');
break;
}
// We 'll need these, as array_shift destroys them
$keys = array_keys($array);
$a = array_shift($array);
$k = array_shift($keys); // Get the key that $a had
$b = permutations($array);
$return = array();
foreach ($a as $v) {
if(is_numeric($v))
{
foreach ($b as $v2) {
// array($k => $v) re-associates $v (each item in $a)
// with the key that $a originally had
// array_combine re-associates each item in $v2 with
// the corresponding key it had in the original array
// Also, using operator+ instead of array_merge
// allows us to not lose the keys once more
$return[] = array($k => $v) + array_combine($keys, $v2);
}
}
}
return $return;
}
See it in action.
By the way, calculating all the permutations recursively is neat, but you might not want to do it in a production environment. You should definitely consider a sanity check that calculates how many permutations there are and doesn't allow processing to continue if they are over some limit, at the very least.

I improved Jon's function by merging his algorithm with the one I had initially. What I did, was check if the function was doing a recursion, if so, I use the original array_merge() (which was working), else I use Jon's array_combine() (to keep the arrays keys).
I'm marking Jon's answer as correct since he proposed a slick solution to keep the array keys intact.
function permutations(array $array, $inb=false)
{
switch (count($array)) {
case 1:
// Return the array as-is; returning the first item
// of the array was confusing and unnecessary
return $array[0];
break;
case 0:
throw new InvalidArgumentException('Requires at least one array');
break;
}
// We 'll need these, as array_shift destroys them
$keys = array_keys($array);
$a = array_shift($array);
$k = array_shift($keys); // Get the key that $a had
$b = permutations($array, 'recursing');
$return = array();
foreach ($a as $v) {
if(is_numeric($v))
{
foreach ($b as $v2) {
// array($k => $v) re-associates $v (each item in $a)
// with the key that $a originally had
// array_combine re-associates each item in $v2 with
// the corresponding key it had in the original array
// Also, using operator+ instead of array_merge
// allows us to not lose the keys once more
if($inb == 'recursing')
$return[] = array_merge(array($v), (array) $v2);
else
$return[] = array($k => $v) + array_combine($keys, $v2);
}
}
}
return $return;
}
Tested successfully with several array combinations.

Related

Add default values to array to fill gaps between indexesif array keys are consecutive [duplicate]

This question already has answers here:
Add elements to array which has gapped numeric keys to form an indexed array / list
(5 answers)
Closed 5 months ago.
I need to check an array for its keys.
If they are consecutive, its good,if not i need to fill in some data.
e.g.
Array
(
[0] => 0
[1] => 1
[2] => 8
[3] => 0
[4] => 0
[5] => 0
[6] => 0
[7] => 0
[8] => 0
[10] => 0
[11] => 0
[12] => 0
[14] => 0
[15] => 0
)
In this case, the indexes 9 and 13 are missing.
To make the example easier, I just want to fill the missing data with the number 999.
My solution however is a little sloppy and doesn't work properly:
$oldK = 0;
foreach($array as $k=>$entry)
{
if($oldK !== $k)
{
$array[$oldK] = 999;
}
$oldK ++;
}
produces following output:
Array
(
[0] => 0
[1] => 1
[2] => 8
[3] => 0
[4] => 0
[5] => 0
[6] => 0
[7] => 0
[8] => 0
[9] => 999
[10] => 999
[11] => 999
[12] => 999
[13] => 999
[14] => 0
[15] => 0
)
is there a smooth way that works?
You may use array_replace combined with array_fill:
$keys = array_keys($a);
$result = array_replace(array_fill(0, max($keys), 999), $a);
Grabbing keys through array_keys first should make it work for any number of elements (provided the keys are numeric, obviously).
Demo: https://3v4l.org/Ik71a
You can use array-fill to create you array and then fill (override) with data from the original array:
$keys = array_keys($arr);
$new = array_fill(min($keys), max($keys),999);
foreach($new as $k => &$v)
if (isset($arr[$k])) $v = $arr[$k];
Notice the & to alter the value in the looping array
Another way to achieve that is with the + operator. Just use ksort afterward if you want the order:
$keys = array_keys($arr);
$new = $arr + array_fill(min($keys), max($keys),999);
ksort($new);
Live example 3v4l
$oldK = 0;
foreach($array as $k=>$entry)
{
if($oldK !== $k)
{
$array[$oldK] = 999;
}
$oldK ++;
}
In your above code, you are advancing the array pointer $k without waiting for keys to fill in a sequential order. To compare $oldK !== $k, the $k needs to be still until $oldK reaches it. Below is the fixed code where in we loop over the keys of the array and do the checks.
$keys = array_keys($array);
$oldK = 0;
while(current($keys) !== false){
$key = current($keys);
if($key === $oldK) next($keys);
else $array[$oldK] = 999;
$oldK++;
}
ksort($array);// to arrange them in sorted order
Demo: https://3v4l.org/GD61j
This should be your complete solution
//4 and 5 is missing in given array1
$arr1 = [0 => 0, 1 => 0, 2 => 8, 3 => 0, 11 => 0, 12 => 0, 15 => 0];
//Create a new array
$arr2 = range(1,max($arr1));
// use array_diff to get the missing numbers and create a new array with them
$missingNumbers = array_diff($arr1,$arr2);
$keys = array_keys($missingNumbers);
$Sonuc = array_replace(array_fill(min($keys), max($keys), 999), $arr1);
print_r($Sonuc);
Demo : https://3v4l.org/TbAho

Subtraction of two array values for same keys and and get result both matched and non-matched value in php

I have two arrays like $a and $b. I want do subtract from $a to $b for the same keys. Also I wanna see the non-matched key of the both array with the subtraction result.
Only matched key will be subtracted. Is it possible without using foreach loop? Not Mandatory that it must be solve without loop. But better if it would be possible without loop.Sample Array is in the below.
$a=Array
(
[1] => 4.00
[2] => 3.00
[3] => 8.00
[4] => 4.88
[5] => 7.88
[10] => 17.88
)
$b=Array
(
[1] => 2.00
[3] => 4.00
[4] => 2.88
[7] => 5.00
[8] => 6.00
)
I wanna the result like
$result=array(
[1] => 2.00
[2] => 3.00
[3] => 4.00
[4] => 2.00
[5] => 7.88
[7] => 5.00
[8] => 6.00
[10] => 17.88
);
My code is:
$res1=$res2=$res3=array();
foreach( $a as $k1=>$v1 ){
foreach($b as $k2=>$v2){
if($k1==$k2){
$res1[$k1]=$v2-$v1;
}else{
$res2[$k2]=v2;
$res3[$k1]=v1;
}
}
}
$res[]=array_merge($res1,$res2,$res3);
echo "<pre>"; print_r($res); echo "</pre>";
But It doesn't give the proper result which I want.
Please try With the below code. Hope it will give your desired output.
$res1=$res2=$res3=array();
foreach( $a as $k1=>$v1 ){
if(isset($b[$k1])){
$res1[$k1]=$a[$k1]-$b[$k1];
}else{
$res2[$k1]=$v1;
}
}
$res3=array_diff_key($b, $a);
$result = array_replace_recursive($res1,$res2,$res3);
echo "<pre>"; print_r($result); echo "</pre>";
You're very close!
$count = count($a) + count($b); // figure out how many times we need to loop - count total # of elements
for ( $key = 1; $key <= $count ; $key++ )
{
if ( isset($a[$key]) && isset($b[$key]) ) $result[$key] = number_format(abs($a[$key] - $b[$key]), 2);
elseif ( isset($a[$key]) ) $result[$key] = number_format($a[$key], 2);
elseif ( isset($b[$key]) ) $result[$key] = number_format($b[$key], 2);
}
The "number_format" and "abs" functions are simply to make the output look exactly like you said you needed.
As the comments mentioned, array_walk is still essentially a loop as it iterates over each element. I've documented the code at each step but the basic idea is to create a merged array and then to alter the values for the duplicate items. There are more efficient ways to go about this, but this illustrates a basic methodology.
I should also point out that because this is using array_walk and an anonymous function (closure), we have to pass in any variables that it needs (... use (...)). If you were to use a foreach loop (or for), you wouldn't need to do this and you could access $output, $first, and $second directly.
https://3v4l.org/WD0t4#v7125
<?php
$first = [
1 => 4.00,
2 => 3.00,
3 => 8.00,
4 => 4.88,
5 => 7.88,
10 => 17.88
];
$second = [
1 => 2.00,
3 => 4.00,
4 => 2.88,
7 => 5.0,
8 => 6.00
];
// Merge the 2 original arrays and preserve the keys
// https://stackoverflow.com/q/17462354/296555
// The duplicate items' value will be clobbered at this point but we don't care. We'll set them in the `array_walk` function.
$output = $first + $second;
// Create an array of the duplicates. We'll use these keys to calculate the difference.
$both = array_intersect_key($first, $second);
// Foreach element in the duplicates, calculate the difference.
// Notice that we're passing in `&$output` by reference so that we are modifying the underlying object and not just a copy of it.
array_walk($both, function($value, $key) use (&$output, $first, $second) {
$output[$key] = $first[$key] - $second[$key];
});
// Finally, sort the final array by its keys.
ksort($output);
var_dump($output);
// Output
//array (size=8)
// 1 => float 2
// 2 => float 3
// 3 => float 4
// 4 => float 2
// 5 => float 7.88
// 7 => float 5
// 8 => float 6
// 10 => float 17.88
And the obligatory condensed version using a foreach loop.
<?php
$first = [
1 => 4.00,
2 => 3.00,
3 => 8.00,
4 => 4.88,
5 => 7.88,
10 => 17.88
];
$second = [
1 => 2.00,
3 => 4.00,
4 => 2.88,
7 => 5.0,
8 => 6.00
];
$output = $first + $second;
foreach (array_keys(array_intersect_key($first, $second)) as $key) {
$output[$key] = $first[$key] - $second[$key];
}
ksort($output);
var_dump($output);
// Output
//array (size=8)
// 1 => float 2
// 2 => float 3
// 3 => float 4
// 4 => float 2
// 5 => float 7.88
// 7 => float 5
// 8 => float 6
// 10 => float 17.88

Search array input key in array

How do I find the keys array of disciplines that have appropriate values?
For Example:
$arr1 = [2, 4, 12];
$result = [...] // Var_dump in link
in_array($arr1, $result);
Regardless of their order, I need to see if there is a set of keys or a no.
But in_array() does not work.
Thanks!
Dump array
Update (01.03.2017)
This is my version of the solution to this problem
$findResult = array_filter($result, function($val)use($get){
$requiredDisciplines = [1, $get['disciplines']['second'], $get['disciplines']['third'], $get['disciplines']['four']]; // запрос
$activePriorities = [];
foreach ($val['disciplines'] as $discipline) {
if (in_array($discipline['id'], $requiredDisciplines)) {
$activePriorities[] = $discipline['priority'];
}
}
for ($i = 0; $i<3; $i++){
if(!in_array($i, $activePriorities))
return false;
}
/*if(in_array(0, $activePriorities) && in_array(1, $activePriorities) && in_array(2, $activePriorities) != true)
return false;*/
// print_r($activePriorities);
return true;
});
I've got a versatile one-liner that will give you all of the arrays containing matches. (so you can derive the keys or the count from that). (demo)
This function is only set to compare the values between the needle and the haystack, but can be set to search keys-values pairs by replacing array_intersect with array_intersect_assoc and adding ,ARRAY_FILTER_USE_BOTH to the end of the filter function (reference: 2nd snippet # https://stackoverflow.com/a/42477435/2943403)
<?php
// haystack array
$result[]=array(1,2,3,4,5,6,7,8,9,10,11,12);
$result[]=array(1,3,5,7,9,11);
$result[]=array(2,4,6,8,10,12);
// needle array
$arr1=array(2,4,12);
//one-liner:
$qualifying_array=array_filter($result,function($val)use($arr1){if(count(array_intersect($val,$arr1))==count($arr1)){return $val;}});
/*
// multi-liner of same function:
$qualifying_array=array_filter(
$result,
function($val)use($arr1){ // pass in array to search
if(count(array_intersect($val,$arr1))==count($arr1)){ // total pairs found = total pairs sought
return $val;
}
}
);*/
echo 'Total sub-arrays which contain the search array($arr1): ',sizeof($qualifying_array),"<br>";
echo 'Keys of sub-arrays which contain the search array($arr1): ',implode(',',array_keys($qualifying_array)),"<br>";
echo 'Is search array($arr1) in the $result array?: ',(sizeof($qualifying_array)?"True":"False"),"<br>";
echo "<pre>";
print_r($qualifying_array);
echo "</pre>";
The output:
Total sub-arrays which contain the search array($arr1): 2
Keys of sub-arrays which contain the search array($arr1): 0,2
Is search array($arr1) in the $result array?: True
Array
(
[0] => Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
[5] => 6
[6] => 7
[7] => 8
[8] => 9
[9] => 10
[10] => 11
[11] => 12
)
[2] => Array
(
[0] => 2
[1] => 4
[2] => 6
[3] => 8
[4] => 10
[5] => 12
)
)

explode an array of delimited strings into two arrays

I have the following array:
Array
(
[0] => 10-7
[1] => 11-3
[2] => 11-7
[3] => 12-3
[4] => 12-7
[5] => 13-3
[6] => 13-7
[7] => 14-3
[8] => 14-7
[9] => 15-7
)
that I need to split into two arrays using "-" as delimiter:
Array
(
[0] => 10
[1] => 11
[2] => 11
[3] => 12
[4] => 12
[5] => 13
[6] => 13
[7] => 14
[8] => 14
[9] => 15
)
and
Array
(
[0] => 7
[1] => 3
[2] => 7
[3] => 3
[4] => 7
[5] => 3
[6] => 7
[7] => 3
[8] => 7
[9] => 7
)
Is there anything like array_explode that does what I want? or a combination of php array functions? I'd like to do this without going through my own for/each loop, if possible, or at least minimize having to reinvent the wheel when something (pseudo)in-built is already out there. I already did this with a for loop. But I can't shake the feeling that there's a more elegant way that smartly uses array functions or anything of that kind. Thanks so much, guys.
Additional info:
Not sure if it matters, but I'm actually after the unique values in the resulting two arrays:
Array
(
[0] => 10
[1] => 11
[2] => 12
[3] => 13
[4] => 14
[5] => 15
)
and
Array
(
[0] => 7
[1] => 3
)
The unique values don't need to be sorted, the keys may be preserved or not, and the legal values of the first array range from 0 to 23, while those of the second 1 to 7. However it's possible to have values other than these (0 to 23 and 1 to 7 or even undelimited stray strings or other data types beyond my control), which I would definitely want to throw out.
The magic bullet you're looking for is array_reduce(), e.g. (PHP 5.3+):
list( $left, $right ) = array_reduce( $input,
function( $memo, $item ) {
list( $l, $r ) = explode( '-', $item );
$memo[0][$l] = $memo[1][$r] = true;
return $memo;
},
array( array(), array() )
);
var_dump( array_keys( $left ), array_keys( $right ) );
You can see it in action here.
With PHP <5.3 you'll have to declare the function ahead of time:
function my_reducer( $memo, $item ) {
list( $l, $r ) = // ...
// ... as above ...
}
list( $left, $right ) = array_reduce(
$input, 'my_reducer',
array( array(), array() )
);
http://codepad.org/TpVUIhM7
<?php
$array = array('7-10','7-11','5-10');
foreach($array as $a){list($x[], $y[]) = explode("-", $a);}
print_r(array_unique($x));
print_r(array_unique($y));
?>
Here Is your Solution, Try to implement following code.
Should work for you.
$main_array = array(
'0' => '10-7',
'1' => '11-3',
'2' => '11-7',
'3' => '12-3',
'4' => '12-7',
'5' => '13-3',
'6' => '13-7',
'7' => '14-3',
'8' => '14-7',
'9' => '15-7',
);
foreach($main_array as $key=>$value)
{
$arr_value = explode('-',$value);
$arr_temp1[] = $arr_value[0];
$arr_temp2[] = $arr_value[1];
}
$arr_temp1_unique = array_unique($arr_temp1);
$arr_temp2_unique = array_unique($arr_temp2);
print "<pre>";
print_r($main_array);
print_r($arr_temp1);
print_r($arr_temp2);
print_r($arr_temp1_unique);
print_r($arr_temp2_unique);
print "</pre>";
As far as I know, there is no suitable PHP function that you can use in this situation.
Functions like array_walk() and array_map() result in a single array, not in multiple arrays.
You said you already have tried a sollution with a loop, but for the sake of helping, here is how I would solve this:
//$data contains the array you want to split
$firstItems = array();
$secondItems = array();
foreach($data as $item)
{
list($first, $second) = explode('-', $item, 2);
$firstItems[$first] = true;
$secondItems[$second] = true;
}
//Now you can get the items with array_keys($firstItems) and array_keys($secondItems);
I'm treating the PHP array as a set by setting the keys instead of the values. This makes that you don't have to use array_unique() to get the unique items.
Try:
foreach($old_array as $array){
$new_2d_array = explode('-', $array);
$new_array_1[] = $new_2d_array[0];
$new_array_2[] = $new_2d_array[1];
}
$new_array_1 = array_unique($new_array_1);
$new_array_2 = array_unique($new_array_2);
Okay, if "The unique values don't need to be sorted, the keys may be preserved or not", then I am going to apply the values to the result arrays as both keys and values to ensure uniqueness without any more function calls after the initial loop.
You can use explode() or sscanf(). explode() has a simpler syntax and only requires the glue substring, whereas sscanf() must parse the whole string and therefore needs a more complicated pattern to match with.
If you didn't need uniqueness, you could simply use:
$hours = [];
$days = [];
foreach ($array as $item) {
sscanf($item, '%d-%d', $hours[], $days[]);
}
or
$hours = [];
$days = [];
foreach ($array as $item) {
[$hours[], $days[]] = explode('-', $item);
}
To ensure uniqueness, just use the isolated values as keys as well.
sscanf() allows you to cast the parsed values directly to integers (Demo)
$hours = [];
$days = [];
foreach ($array as $item) {
[0 => $hour, 1 => $day, 0 => $hours[$hour], 1 => $days[$day]] = sscanf($item, '%d-%d');
}
explode() will only produce string-type values. (Demo)
$hours = [];
$days = [];
foreach ($array as $item) {
[0 => $hour, 1 => $day, 0 => $hours[$hour], 1 => $days[$day]] = explode('-', $item);
}
All of the above snippets rely on "array destructuring" syntax instead of calling list(). If you are wondering why the keys are repeated while destructuring, see this post.

Minimum Match Logic

I have a very large data set that I'm trying to find the smallest set that will satisfy all the data sets. The final set must have one value in it that is in all of the data sets
A small sample of the data looks like
[0] => Array
(
[0] => 21
[1] => 21
[2] => 21
)
[1] => Array
(
[0] => 29
)
[2] => Array
(
[0] => 27
)
[3] => Array
(
[0] => 21
[1] => 21
[2] => 21
[3] => 39
[4] => 39
[5] => 43
)
[4] => Array
(
[0] => 29
[1] => 33
[2] => 33
[3] => 43
)
In this case I need logic to return 21, 27 and 29
The values returned needs to be be the minium number of values that match all arrays. Since I'm a PHP programmer, I writing this function in PHP.
You could follow this algorithm:
Updated after testing
$data=array(
array(21,29,27,57,22),
array(22,21,23,24,25,26),
array(31)
);
$map = array(); // keep a map of values and how many times they occur in other sets
foreach ($data as $setid => $set) {
foreach (array_unique($set) as $v) {
$map[$v][$setid] = true;
}
}
function reverseCount(array $a, array $b)
{
return count($b) - count($a);
}
// sort reversed on intersection count
uasort($map, 'reverseCount');
// after sorting the first number will be the one that occurs the most
// keep track of which sets have been hit
$setmap = array(); $n = count($data);
foreach ($map as $v => $sets) {
$hits = 0;
foreach ($sets as $setid => $dummy) {
if (!isset($setmap[$setid])) {
--$n;
++$hits;
$setmap[$setid] = true;
} else {
continue;
}
}
if ($hits) {
echo "value $v\n";
if (!$n) {
// all sets are hit
break;
}
}
}
Tested this time. It's not proven to always get the right result, because this is considered a greedy approximation algorithm.
But I hope it gives an idea of what you could do. Let me know if anything confuses you or if I'm dead wrong about it :)

Categories