Minimum Match Logic - php

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

Related

compare values in array and delete it from array - php

array:
[0] => Array
(
[0] => A
[1] => 70H
[2] => 51.57
[3] => RH
)
[1] => Array
(
[0] => B
[1] => 70H
[2] => 39.11
[3] => RH
)
[2] => Array
(
[0] => C
[1] => 70H
[2] => 12.11
[3] => RH
)
This is just an example of an array, my real array is really big.
I want to find the same values in array like this [key][1], compare their price, find the lowest PRICE [KEY][2]and save [key][0] for all other elements, if the price is the same then random save one as lowest. In the example i give the result that i want will be:
[0] A
[1] B
I tried this code but it doesn't work for me:
$res=array();
$Mfr= arrays_column($final_array, 1);
$dupes = array_diffs(array_count_values($Mfr), array(1)); // how many times a mfr sku appears
print "\nThese are repetitive values:\n[mfrsku] => (number of reps)\n";
foreach($dupes as $key => $val){
$temp = array_intersect_key(arrays_column($final_array, 3), $key);
if(count(array_unique($temp)) < count($temp)){
$temp = array_intersect_key(arrays_column($final_array, 2), array_intersect($Mfr, array($key)));
$temp = array_diffs($temp, array(min($temp)));
$res[] = array_intersect_key(arrays_column($final_array, 0), $temp);
print_r($res);die;
}
}
You can collect during first foreach loop all minimum values and then easily collect records which have another values:
Declaring arrays
$minvals = []; // array of minimum values
$spec = []; // resultant array
$tmp = []; // tmp array (needs for similar records)
First array (collecting minimum values(prices)):
foreach($ar as $rec){
$val = $rec[2]; // price
if(isset($minvals[$rec[1]] )) { // next appearance of the same $rec[1]
if ($minvals[$rec[1]] >= $val) {
$minvals[$rec[1]] = $val;
}
} else { // first appearance
$minvals[$rec[1]] = $val;
}
}
Now you can collect desired values of from the first column:
foreach($ar as $rec){
if ($rec[2] > $minvals[$rec[1]]){ // if price is bigger than minimum
$spec[] = $rec[0];
} else if($rec[2] == $minvals[$rec[1]]){ // if equal
if(isset($tmp[$rec[1]])){ // if it appears at not the first time
$spec[] = $rec[0];
} else {
$tmp[$rec[1]] = 1;
}
}
}
In case of input array like:
$ar = [ ["A","70H","51.57","RH"],
["B","70H","39.11","RH"],
["C","70H","12.11","RH"],
["A2","71H","11.57","RH"],
["B2","71H","32.11","RH"],
["C2","73H","12.11","RH"],
["C3","73H","11.11","RH"],
["C4","73H","33.11","RH"],
["C5","73H","3.11","RH"],
["C6","73H","3.11","RH"],
];
Outputs would be next:
Array
(
[0] => A
[1] => B
[2] => B2
[3] => C2
[4] => C3
[5] => C4
[6] => C6
)
Demo

How to merge two arrays with duplicate keys

I have two arrays $rate_row and $totalrowcost I am trying to update a row in the second array $totalrowcost based on the key in the first array $rate_row both arrays are always the same length.
I combine both arrays using the array_combine function
my code below works if there are no duplicate keys in the array but if i combine them when there are duplicate keys
I don't get the desired result.
Example:
If the key in $rate_row is 0 I need to set the value in $totalrowcost to 0 but when combining the array, one of the rows gets dropped and only one row with a key of 0 is preserved.
I've since learned since trying to figure this out that PHP will not allow an array to have a duplicate key, but i was wondering if there is some type of work around or hack that can help any ideas would be great thanks.
enter code here
<?php
// Finds the lowest duty rate
$lowest = 0;
$row_combine = array_combine($rate_row, $totalrowcost);
foreach($row_combine as $a => $combine_row):
if ($a = 0){
$lowest = $a;
echo "";
}
endforeach;
// Finds the row value associated with the lowest duty rate
foreach($row_combine as $a => $combine_row):
if ($a === $lowest){
$lowest1 = $combine_row;
}
endforeach;
for($i = 0; $i < count($totalrowcost); $i++) {
enter code here
if ($totalrowcost[$i] == $lowest1){
$totalrowcost[$i] = 0;
}
}?>
enter code here
$rate_row
Array
(
[0] => 35
[1] => 0
[2] => 40
[3] => 0
[4] => 45
)
$totalrowcost
Array (
[0] => 100
[1] => 49.99
[2] => 102
[3] => 98
[4] => 125
)
$row_combine Output
Array (
[35] => 100
[0] => 98
[40] => 102
[45] => 125
)
Desired $row_combine Output
Array (
[35] => 100
[0] => 49.99
[40] => 102
[0] => 98
[45] => 125
)
Actual Output updated
$totalrowcost
Array (
[0] => 100
[1] => 49.99
[2] => 102
[3] => 0
[4] => 125
)
Desired Output updated
$totalrowcost
Array (
[0] => 100
[1] => 0
[2] => 102
[3] => 0
[4] => 125
)
documentation for class to read up on the syntax and more information about them.
I'm a little unclear as to what problem you are trying to solve, perhaps an edit on what the use case is might help suggest other options.
EDIT:
<?php
// you can use whatever input $rate_row is from user input or such along with the $totalrowcost
$rate_row = [35, 0, 40, 0, 45];
$totalrowcost = [100, 49.99, 102, 98, 125];
class Table {
public $row_items;
public $row_rates;
public $row_rate_applied;
private $lowestRate;
// used to init class values
function __construct($items, $rates) {
// set variables to class
// might want to run validation here to make sure the count is = for $items and $rates
$this->row_items = $items;
$this->row_rates = $rates;
$this->lowestRate = min($rates); // add validation to make sure rates is array http://php.net/manual/en/function.min.php
// main guts that are used to solve your problem is inside this loop
for($i = 0; $i < count($items); $i++) {
// here we test if rates index == lowest. if it is set the item value to lowest
if ($rates[$i] == $this->lowestRate) {
$this->row_rate_applied[$i] = $this->lowestRate;
} else {
$this->row_rate_applied[$i] = $items[$i];
}
}
}
}
$table = new Table($totalrowcost, $rate_row);
echo var_dump($table->row_rate_applied);
The above code builds up and applies the rates against the items. I'm not 100% what the expected result is actually supposed to be because the code originally posted doesn't make a ton of sense for the expected output
essentially the idea is to build your Row
If the keys have no significant value (i.e. you just want to later loop over the final array) you can make sure the keys are unique before you merge them by appending a random name at the end of them.
Here is a function that merges two arrays while keeping the duplicate keys.
function array_uniqify_keys($array,$append='',$glue='--'){
if($append === ''){
$append = uniqid() . mt_rand(1000,9999);
}
foreach($array as $key => $value){
unset($array[$key]);
$array[$key.$glue.$append] = $value;
}
return $array;
}
function array_merge_duplicate_safe($array1,$array2,$a1_name='',$a2_name=''){
$array1 = array_uniqify_keys($array1,$a1_name);
$array2 = array_uniqify_keys($array2,$a2_name);
return array_merge($array1,$array2);
}
$array1 = [
1 => 'foo',
2 => 'boo'
];
$array2 = [
1 => 'good',
2 => 'bad',
3 => 'ugly'
];
print_r(array_merge_duplicate_safe($array1,$array2));
The result for the above code is:
Array
(
[1--59d393950489c8380] => foo
[2--59d393950489c8380] => boo
[1--59d39395049197021] => good
[2--59d39395049197021] => bad
[3--59d39395049197021] => ugly
)
You can also get the old key by explode('--',$key)[0].

in_array() is not working while calling php script in Yii2

I have called core php function from controller of Yii2 in that in_array() function is not working but I have called individually then it is working.
following is my array which I have passed searchForId().
Array
(
[1] => Array
(
[2] => PRICE:
)
[4] => Array
(
[1] => S/NO
[3] => INSULATED TANK SIZE
[7] => QTY
[8] => U.PRICE(Qr.)
[10] => TOTAL PRICE (Qr.)
)
[5] => Array
(
[1] => 01
[3] => FZ 198(S) (11 x 6 x 3MH)
w/p (3+3)
[7] => 1 SET
[8] => 390,197.00
[10] => 390,197.00
)
[6] => Array
(
[1] => 02
[3] => FZ 36(S) (2 x 6 x 3MH)
w/p (3+3)
[7] => 1 SET
[8] => 121,232.00
[10] => 121,232.00
)
[7] => Array
(
[8] => Total in QAR
[10] => 511,429.00
)
)
this type of array I have got from excel sheet which I have read.
and my function is:
public function searchForId($array) {
foreach ($array as $key => $val) {
if (in_array('S/NO', $val)) {
return $key;
}
}
return null;
}
where I am doing wrong please help me.Thank You in advance!!
It seems to me you just need to do:
<?php
$array = [
"S/NO",
"INSULATED TANK SIZE",
"QTY",
"U.PRICE(Qr.)",
"TOTAL PRICE (Qr.)"
];
public function searchForId($array) {
$key = array_search('S/NO', $array);
return $key;
}
var_dump(searchForId($array));
Results here.
array_search() returns you the key already, or false if value is not found. Using in_array you won't directly get the key, if that's your aim. You could check if the return value is false|null at the place you call this function. I would do return $key ?? null(php 7+)
UPDATE
Here's how you can do with the last array you have given. Also see here.
public function searchForId($array) {
foreach($array as $k => $sub){
$key = array_search('S/NO', $sub);
if($key !== false){
return $key;
} else {
continue;
}
}
return null;
}
var_dump(searchForId($array));
Since the $key is int(0), and in all other cases you get bool(false) from array_search, you should check whether the $key is literally false and if so, continue to the next array :-)
Change your if statement as
if (in_array('S/NO', $val)) {
Well, the most reliable would to use array_search which would eliminate your whole function -
$key = array_search('S/NO', $array); //will return 1 for S/No and 7 for QTY.
Write array search inside your searchForId() function or try by trimming the values of array like shown above.

How to remove duplicate entries from associative array in php

My array is
Array
(
[0] => Array
(
[id] => 20
[new_id] => 958
[affiliate_id] => 33
)
[1] => Array
(
[id] => 21
[new_id] => 959
[affiliate_id] => 45
)
[2] => Array
(
[id] => 22
[new_id] => 960
[affiliate_id] => 23
)
[3] => Array
(
[id] => 23
[new_id] => 961
[affiliate_id] => 33
)
)
and i want array
Array
(
[0] => Array
(
[id] => 20
[new_id] => 958
[affiliate_id] => 33
)
[1] => Array
(
[id] => 21
[new_id] => 959
[affiliate_id] => 45
)
[2] => Array
(
[id] => 22
[new_id] => 960
[affiliate_id] => 23
)
)
I want to remove duplicates value of affiliate_id . According to first array i am getting affiliate_id's value is 33 for two time. But i want it for one time. So in my second array (which will be my answer) i remove it.
Try something like this, not so pretty as array_ one liners, but still:
$existing_aff_ids = array();
$unique = array();
foreach ($affiliate as $aff) {
if (!isset($existing_aff_ids[$aff['affiliate_id']])) {
$unique[] = $aff;
$existing_aff_ids[$aff['affiliate_id']] = 1;
}
}
Given $affiliates as in your answer, looping over the array and checking for affiliate_id would do the trick
$unique_affiliates = array();
foreach($affiliates as $affiliate) {
$affiliate_key = $affiliate['key'];
/* Variant 1 */
$unique_affiliates[$affiliate_key] = $affiliate;
/* Variant 2 */
if(!isset($unique_affiliates[$affiliate_key])) {
$unique_affiliates[$affiliate_key] = $affiliate;
}
}
All entries in $unique_affiliates will have unique affiliate_keys. Variant 1 will contain the last occurrence of each afffiliate_key (as in your example), whereas variant 2 will add the first occurrence of any affiliate_key and just ignore all subsequent ones.
These are not duplicate values :
1. $input = array_map("unserialize",
array_unique(array_map("serialize", $data))
2. array_values(array_unique($data))
Both this case fails because of the unique id values are there it requires all values to be same to consider it as duplicate.
Solution:Will making the array check the value of the corresponding field.
foreach($data as $key=>$val)
{
if (is_array($val))
{
$val2 = arrayUnique($val);
}
else
{
$val2 = $val;
$newArray=array_unique($data);
$newArray=deleteEmpty($newArray);
break;
}
if (!empty($val2))
{
$newArray[$key] = $val2;
}
}
print_r($newArray);

Array permutations in multidimensional array keeping the keys 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.

Categories