Order Multiple Arrays (Including Each Other) - php

Let's say we have arrays like below.
$arr00 = [0,1,2,...,9]; // It includes 9 arrays. So the score should be 9.
$arr01 = [0,1,...,8]; // score = 8
...
$arr09 = [0]; // score = 0
ArrScore (definition): If an array include an array with all elements it
gets one point. So in this case $arr00's total score is 9. Because it
includes all other 9 arrays. And $arr09's score will be 0.
Actual Conditions
Our array elements could be random numbers. (not sequent orders ascending +1)
There could be thousands of arrays.
Our arrays are always flat. (no duplicated element in an array)
We are using php (any theoretical approach is also ok)
Think that you have a standard PC and you will order these arrays everyday once. (No need for the result of "which arr eats which ones". Just ArrScores.)
Goal is to order arrays by ArrScore. And we need ArrScores. What should be the approach? (Theoretical or practical)

If I understood right, this might help:
function compare($a,$b) {
if(count(array_intersect($a, $b)) == count($a)) return -1;
else return 1;
}
$arr0 = [0,2,4,7];
$arr1 = [7,0,2,9,4];
$arr2 = [4,2];
$arr = [$arr0,$arr1,$arr2];
usort($arr,"compare");
foreach($arr as $a) {
print_r($a);
}
prints:
Array ( [0] => 4 [1] => 2 ) Array ( [0] => 0 [1] => 2 [2] => 4 [3] => 7 ) Array ( [0] => 7 [1] => 0 [2] => 2 [3] => 9 [4] => 4 )
EDIT:
Compute the ArrayScore for each array:
$arr0 = [0,2,4,7];
$arr1 = [7,0,2,9,4];
$arr2 = [4,2];
$arr = [$arr0,$arr1,$arr2];
$arrayScores = [];
//initialize the Scores with 0
foreach($arr as $a){
$arrayScores[] = 0;
}
//run through all arrays
for($i=0;$i<count($arr);$i++){
//with $j=$i+1, every combination is only checked once
for($j=$i+1; $j<count($arr);$j++){
if(count(array_intersect($arr[$j], $arr[$i])) == count($arr[$j])) {
$arrayScores[$i]++;
}
if(count(array_intersect($arr[$i], $arr[$j])) == count($arr[$i])){
$arrayScores[$j]++;
}
}
}

Related

Split an array into three similar Sum

I would like to split an array into three array that have similar sums - as close as possible
I have array
$arr = [1,2,4,7,1,6,2,8];
Desire output for example:
a = 8,2 // as sum is 10
b = 7,2,1 // as sum is 10
c = 6,4,1 // as sum is 10
Thanks
You can use the following algorithm:
Sort the input array from big to small
Create output array
for each element in the input - insert to the lowest sum in the output array.
Consider the following code:
$arr = [1,2,4,7,1,6,2,8];
sort($arr);
$arr = array_reverse($arr); // big to small
$out = array(array(),array(),array()); // output array
for($i = 0; $i < 8; $i++) {
$sums = array_map("array_sum" ,$out); // get all current sums of the array
$index = array_keys($sums, min($sums))[0]; // get the min sum
$out[$index][] = $arr[$i]; // add the element to the array with the lowest sum
}
echo print_r($out, true);
Now you will get:
array:
[0]: array:
[0] => 8
[1] => 2
[2] => 1
[1]: array:
[0] => 7
[1] => 2
[2] => 1
[2]: array:
[0] => 6
[1] => 4

How can I select 2 items each in an array making sure every set is outputed

Lets say I have an array of numbers: [1,2,3].
How can I loop through this array to create an array of possible permutations.
I'm expecting outputs like:
[1,2], [1,3], [2,1], [2,3], [3,1], [3,2].
Simple nested loops required for the same input array
Do the following:
$input = array(1,2,3);
$output = array();
// to get all possible permutations
// for first value in the permutation, loop over all array values
foreach ($input as $value1) {
// for second value in the permutation, loop again similarly
foreach ($input as $value2) {
if ($value1 !== $value2) // dont consider same values
$output[] = array($value1, $value2);
}
}
If i understand the question correctly, you want to have an array containing X amount of integers and get every possible combination of two distinct integers from that array?
This can be done with two for loops, one to loop through each of your array's elements, and another that combines that element with every other element.
for(int $x = 0; $x < count($arr1); $x++) {
for(int $y = 0; $y < count($arr1); $y++) {
if ($x == $y || $arr1[$x] == $arr1[$y]) {
continue;
} else {
array_push($output, [$arr1[$x], $arr1[$y]]);
}
}
}
Looking at your example I assumed you don't want repeating numbers. So I did a loop with an inner loop and compared the numbers before adding to the print Array! My first stackoverflow submissions so I'd love some feedback!
$arrayToParse = [1, 2, 3];
$arrayToPrint = [];
foreach($arrayToParse as $num1){
foreach($arrayToParse as $num2){
if($num1 != $num2){
array_push($arrayToPrint, [$num1, $num2]);
}
}
}
print_r($arrayToPrint);
// OUTPUT
Array
(
[0] => Array
(
[0] => 1
[1] => 2
)
[1] => Array
(
[0] => 1
[1] => 3
)
[2] => Array
(
[0] => 2
[1] => 1
)
[3] => Array
(
[0] => 2
[1] => 3
)
[4] => Array
(
[0] => 3
[1] => 1
)
[5] => Array
(
[0] => 3
[1] => 2
)
)

PHP: take out duplicate digits from an array then print them out

I'm probably [super]overthinking this. I'm trying to analyze an array with values like [1,9], [4,6] [5,5], [6,4], [9,1] and duplicate digits (I'm having a super brain fart and can't even remember the term for numbers like this) remove (the last two) so that only [1,9], [4,6] [5,5] are printed.
I was thinking that turning this array into a string and using preg_match, but I'm pretty sure this wouldn't work even if I had the correct regex.
If you have an array of pairs like this:
$x = array(
array(1,9),
array(4,6),
array(5,5),
array(6,4),
array(9,1)
);
Here is one way to get the unique pairs:
foreach ($x as $pair) {
sort($pair);
$unique_pairs[implode(',', $pair)] = $pair;
}
This uses string representations of each sorted pair as keys in a new array, so the result will have distinct values by definition.
As far as the printing them out part of your question, once you have the unique values you can loop over them and print them out in whichever format you like, for example:
foreach ($unique_pairs as $pair) { vprintf("[%d,%d]<br>", $pair); }
It looks like elements are distributed symmetrically.
We can cut the array in two halves and get only the first half with array_slice():
$array = array(
array(1,9),
array(4,6),
array(5,5),
array(6,4),
array(9,1),
);
print_r(array_slice($array, 0, ceil(count($array) / 2)));
Result:
Array(
[0] => Array(
[0] => 1
[1] => 9
)
[1] => Array(
[0] => 4
[1] => 6
)
[2] => Array(
[0] => 5
[1] => 5
)
)
Demo at Codepad.
ceil() is used to round the number up to the next highest integer if there is an even number of items in the array. Example: if there is 3 items in the array, 5 / 2 will return 2.5, we want 3 items so we use ceil(2.5) which gives 3.
Example with 3 items:
$array = array(
array(1,9),
array(5,5),
array(9,1),
);
print_r(array_slice($array, 0, ceil(count($array) / 2)));
Result:
Array(
[0] => Array(
[0] => 1
[1] => 9
)
[1] => Array(
[0] => 5
[1] => 5
)
)
Example with 4 items:
$array = array(
array(1,9),
array(7,7),
array(7,7),
array(9,1),
);
print_r(array_slice($array, 0, ceil(count($array) / 2)));
Result:
Array(
[0] => Array(
[0] => 1
[1] => 9
)
[1] => Array(
[0] => 7
[1] => 7
)
)
If I'm correct in understanding what you are trying to do, you want to remove the final 2 elements from the array?
There is a function in PHP called array_pop that removes the final element from the array.
$array = array_pop($array);
So if you run this twice, you will remove the final 2 elements from the array.
This is how I'd do it (and I hope I am not overthinking this :))
$stringArray = array();
$stringArray[] = '1,9';
$stringArray[] = '4,6';
$stringArray[] = '5,5';
$stringArray[] = '6,4';
$stringArray[] = '9,1';
foreach($stringArray as &$numString) {
$numString = explode(',', $numString);
usort($numString, function($a, $b) {return $a - $b;});
$numString = implode(',', $numString);
}
$a = array_unique($a);
print_r($a);
You basically explode every element into a subarray, sort it and then implode it back. After calling the array_unique, you're left with unique values in the array.
The output would be
Array
(
[0] => 1,9
[1] => 4,6
[2] => 5,5
)
The result you suggest treats [a,b] as equivalent to [b,a] which makes the problem a lot more complex. The code below gives the result you asked for, but without really understanding what the problem is that you are trying to fix and whether [1,9] is equivalent to [9,1] in the solution:
$a=array(array(1,9),array(4,6),...
$dup=array();
for ($i=0; $i<count($a) -1; $i++) {
for ($j=$i+1; $j<count($a); $j++) {
if (($a[$i][0]==$a[$j[0] && $a[$i][1]==$a[$j[1])
|| ($a[$i][0]==$a[$j[1] && $a[$i][1]==$a[$j[0])) {
$dup[]=$j;
}
}
}
foreach ($dup as $i) {
unset($a[$i]);
}
So I'm actually going to assume your question to have a different meaning than everyone else did. I believe what you're asking is:
How do you filter out array items where a reverse of the item has already been used?
<?php
// The example set you gave
$numberSets = [[1, 9], [4, 6], [5, 5], [6, 4], [9, 1]];
// Initialize an empty array to keep track of what we've seen
$keys = [];
// We use array filter to get rid of items we don't want
// (Notice that we use & on $keys, so that we can update the variable in the global scope)
$numberSets = array_filter($numberSets, function($set) use(&$keys) {
// Reverse the array
$set = array_reverse($set);
// Create a string of the items
$key = implode('', $set);
// Get the reverse of the numbers
$reversedKey = strrev($key);
// If the palindrome of our string was used, return false to filter
if (isset($keys[$reversedKey])) {
return false;
}
// Set the key so it's not used again
// Since $keys is being passed by reference it is updated in global scope
$keys[$key] = true;
// Return true to NOT filter this item, since it or it's reverse were not matched
return true;
});
var_dump($numberSets);

Flatten 2D Array Into Separate Indexed Arrays

I have the array:
$total =array();
Array (
[0] => Array
(
[0] => 1
[1] => 3
)
[1] => Array
(
[0] => 6
[1] => 7
[2] => 8
)
[2] => Array
(
[0] => 9
[1] => 10
)
)
I need to dynamically change each array into an indexed array for a Cartesian function.
Here is how I need the code to look for the function to work correctly:
$count = cartesian(
Array(1,3),
Array(6,7,8),
Array(9,10)
);
Any help would be greatly appreciated! I have tried flattening, looping, using array_values, using just the array itself and I keep falling short.
Thanks
Nick
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;
}
$count = call_user_func('cartesian', array($total));
print_r($count);
Your arrays already look exactly the way you want them to. array(1,3) is the same as array(0 => 1, 1 => 3) and both are an array with the value 1 at key 0 and 3 at key 1. Exactly what the debug output shows you.
It seems you just need to pass them as separate arguments to the function. E.g.:
cartesian($total[0], $total[1], $total[2])
For dynamic lengths of arrays, do:
call_user_func_array('cartesian', $total)
I believe that your $total array is multi-dimensional array with numeric indexed. So yo can try like this
$count = cartesian($total[0], $total[1], $total[2]);

How to group array values to different levels in PHP?

$arr = array(25,41,120,...36);
How to group values in $arr to specified integer range $start ~ $end ?
For example , if the level range is 1~5(1,2,3,4,5), how can I specify a level for each element of $arr ?
The only principle is that larger value should map to larger level, and should cover the entire level range as possible.
UPDATE
I'll give a maybe over simplified example:
if the levels are 1~4, and the $arr is array(25,41,120,36),then obviously the best way to assign level numbers should be:
25 -> 1
41 -> 3
120 -> 4
36 -> 2
Frist, sort it: http://php.net/manual/en/function.sort.php (and if your array has associative keys, check out asort() )
Then, I would make a new array that would hold your result. Iterate though $arr and if do a check that the value is between your bounds. If it is, add it to the new array.
$NewArray = array();
$arr = sort($arr);
$i = 0;
while ($i < count($arr))
{
if ($arr[$i] <= $HighValue && $arr[$i] >= $LowValue)
{
$NewArray[] = $arr[$i];
}
$i++;
}
Maybe you can try this:
$inputarr = array(1,3,5,7,2,4,6,8);
$levelcount = 3; //assume you have 3 levels
$csize = ceil(count($inputarr)/$levelcount);
sort($inputarr);
print_r(array_chunk($inputarr,$csize,true))
The output is
Array
(
[0] => Array
(
[0] => 1
[1] => 2
[2] => 3
)
[1] => Array
(
[3] => 4
[4] => 5
[5] => 6
)
[2] => Array
(
[6] => 7
[7] => 8
)
)
I do not quite understand how you want to associate the numbers to their level. Presumably you want the number as the key and the level as the value in an associative array. At least that is what your example looked like.
Also, I do not understand the function of $start and $end. If $start is 5 and $end is 50, but there are only 10 numbers, what happens? What if $start is 2 and $end is 7 and there are 10 numbers? I replaced the mechanism with just $levelOffset. It is my guess as to what you really wanted.
<?php
$levelOffset = 1;
$arr = array(25,41,120,36);
sort($arr);
$arr = array_flip($arr);
foreach ($arr as &$level) {
$level += $levelOffset;
}
/*
var_dump($arr) gives:
array(4) {
[25]=>
int(1)
[36]=>
int(2)
[41]=>
int(3)
[120]=>
&int(4)
}
*/

Categories