How to count an array with condition - php

I have a list of hosts with interface.
The code must count the repeated interfaces per host.
Also at the end the code must show the repeating interfaces X times, per host.
I am asking this because I want to send an alert that X host has a failing X interface or more failing interfaces.
$data = array(
array("192.168.0.1","eth1"),
array("192.168.0.2","eth2"),
array("192.168.0.3","eth3"),
array("192.168.0.1","eth1"),
array("192.168.0.4","eth1"),
array("192.168.0.2","eth5")
);
I followed other examples in here, but most of them are for simple arrays or if multidimensional example then the examples aren't similar.
I have tried this...
<?php
$data = array(
array("192.168.0.1","eth1"),
array("192.168.0.2","eth2"),
array("192.168.0.3","eth3"),
array("192.168.0.1","eth1"),
array("192.168.0.4","eth1"),
array("192.168.0.2","eth5")
);
$counter_data = count($data);
$duplicated_host = array_filter(array_count_values(array_column($data, 0)), function($v) { return $v > 1; });
print_r($duplicated_host);
print ("<br>");
$duplicated_host_keys = (array_keys($duplicated_host));
for ($row_num = 0; $row_num < $counter_data; $row_num++)
{
$host = $data[$row_num][0];
$interface = $data[$row_num][1];
if (in_array($host,$duplicated_host_keys))
{
print($host . " " . $interface . "<br>");
}
}
The code above is wrong, somewhat working but it is not what I expect...
Is there a simple way to do this?
At the end the output should look like:
Host 192.168.0.1 has eth1 repeated 2 times. --> For current data only
Host 192.168.0.1 has eth9 repeated 5 times.
Host 192.168.0.4 has eth1 repeated 9 times.

You'll need to group double, first host, then by interface.
Then you can looop over this grouping array to show/send the output:
<?php
$data = array(
array("192.168.0.1","eth1"),
array("192.168.0.2","eth2"),
array("192.168.0.3","eth3"),
array("192.168.0.1","eth1"),
array("192.168.0.4","eth1"),
array("192.168.0.2","eth5")
);
$result = [];
foreach ($data as $arr) {
[ $host, $nic ] = $arr;
if (!isset($result[$host])) {
$result[$host] = [];
}
if (!isset($result[$host][$nic])) {
$result[$host][$nic] = 0;
}
$result[$host][$nic]++;
}
foreach ($result as $host => $nics) {
foreach ($nics as $nic => $count) {
echo "${host} has his '${nic}' interface fail ${count} time(s)" . PHP_EOL;
}
}
192.168.0.1 has his 'eth1' interface fail 2 time(s)
192.168.0.2 has his 'eth2' interface fail 1 time(s)
192.168.0.2 has his 'eth5' interface fail 1 time(s)
192.168.0.3 has his 'eth3' interface fail 1 time(s)
192.168.0.4 has his 'eth1' interface fail 1 time(s)
Try it online!
NIC --> 'Network Interface Card'

This probably is what you are looking for:
<?php
$input = array(
array("192.168.0.1","eth1"),
array("192.168.0.2","eth2"),
array("192.168.0.3","eth3"),
array("192.168.0.1","eth1"),
array("192.168.0.4","eth1"),
array("192.168.0.2","eth5"),
);
$output = [];
array_walk($input, function($entry) use (&$output) {
[$host, $interface] = $entry;
if (isset($host, $output) && isset($interface, $output[$host])) {
$output[$host][$interface]++;
} else {
$output[$host][$interface] = 1;
}
});
print_r($output);
The output is:
Array
(
[192.168.0.1] => Array
(
[eth1] => 2
)
[192.168.0.2] => Array
(
[eth2] => 1
[eth5] => 1
)
[192.168.0.3] => Array
(
[eth3] => 1
)
[192.168.0.4] => Array
(
[eth1] => 1
)
)

Related

replace values of keys in json1 from Json2

I am very very new to php.. actually i am from java domain. But, i have to do some work in php for integration. My scenario is, i have one json array which will have 4 keys for ex:
one json --> {"id":7,"active":1,"blogId":"abc","blog_heading":"xyz"}.
I will be getting another JSON which ever edited from admin panel. for example if i updated any key, only that key will coming in the
second JSON --> for ex: {"blog_heading":"def"}
Now, i have to replace the value of second json to first json. example output for above scenario like I am very very new to php.. actually i am from java domain. But, i have to do some work in php for integration. My scenario is, i have one json array which will have 4 keys for ex:
output json --> {"id":7,"active":1,"blogId":"abc","blog_heading":"def"}.
So i am trying as below,
$id = json_decode($data_string);
$id2 = json_encode($post);
$id5 = json_decode($id2);
$id6 = array();
foreach ($id as $key => $value)
{
$log->debug($key . ': ' . $value);
if (array_key_exists($key, $id5->data)) {
$log->debug($key . 'element is in the array');
$log->debug($value . 'element is in the array');
//array_push($id5, "apple", "raspberry");
$id3 = array($key => $value);
$id3[$key] = $value;
$log->debug($id3);
}else{
$log->debug($key . 'element is not in the array');
}
}
$id7 = json_encode($id2);
$log->debug($id7);
id5 data is : $id5
DEBUG - 2017-06-05T02:26:20-04:00 - stdClass Object
(
[meta] => stdClass Object
(
[table] => story
[type] => item
)
[data] => stdClass Object
(
[id] => 7
[active] => 1
[blogId] => abc
[blog_heading] => xyz
)
)
==================
Log of $id :
stdClass Object
(
[active] => 1
[blog_heading] => def
[id] => 7
)
Please suggest me how can i achieve this... Anything i am doing wrong here
Please try that:
$j1 = '{"id":7,"active":1,"blogId":"abc","blog_heading":"xyz"}';
$j2 = '{"blog_heading":"def"}';
$result = json_encode(
array_merge(
json_decode($j1, true),
json_decode($j2, true)
)
);
<?php
$json1='{"id":7,"active":1,"blogId":"abc","blog_heading":"xyz"}';
$json2='{"blog_heading":"def"}';
$json1=json_decode($json1);
$json2=json_decode($json2);
foreach ($json1 as $key => $value) {
if($json2->$key){
$json1->$key=$json2->$key;
}
}
$json1=json_encode($json1);
$json2=json_encode($json2);
If you have only one element in array,Do like this
$a = json_decode('{"id":7,"active":1,"blogId":"abc","blog_heading":"xyz"}',true);
$b = json_decode('{"blog_heading":"def"}',true);
$a['blog_heading'] = $b['blog_heading'];
print_r($a);
If you have multiple element like this :
$c = json_decode('[{"id":7,"active":1,"blogId":"abc","blog_heading":"xyz"},
{"id":8,"active":1,"blogId":"abc","blog_heading":"xyz"}]',true);
$d = json_decode('[{"blog_heading":"def"},{"blog_heading":"hello"}]',true);
$return = array();
for ($i=0; $i < count($c); $i++) {
$c[$i]['blog_heading'] = $d[$i]['blog_heading'];
$return[] = $c[$i];
}
print_r($return);
If you want to replace value by specific id
$c = json_decode('[{"id":7,"active":1,"blogId":"abc","blog_heading":"xyz"},
{"id":8,"active":1,"blogId":"abc","blog_heading":"xyz"}]',true);
$d = json_decode('[{"id":7,"blog_heading":"def"},{"id":9,"blog_heading":"hello"}]',true);
$return = array();
for ($i=0; $i < count($c); $i++) {
if($d[$i]['id'] == $c[$i]['id']) {
$c[$i]['blog_heading'] = $d[$i]['blog_heading'];
}
$return[] = $c[$i];
}
print_r($return);
Checking dynamic key value pair :
$c = json_decode('[{"id":7,"active":1,"blogId":"abc","blog_heading":"xyz"},
{"id":8,"active":1,"blogId":"abc","blog_heading":"xyz"}]',true);
$d = json_decode('[{"id":6,"blog_heading":"def"},{"id":9,"blog_heading":"hello"}]',true);
$return = array();
for ($i=0; $i < count($c); $i++) {
$result = array_intersect_key($c[$i], $d[$i]);
foreach ($result as $key => $value) {
$c[$i][$key] = $d[$i][$key];
}
$return[] = $c[$i];
}
print_r($return);
Check demo here

Sum up array first, then push into array loop solution

I had a problem with this particular code. The conditions are:
When $rows['Machine#'] is not in array, push in $machineArr array and unset the $totalTimeArr array.
When $rows['Machine#'] is in the array, push $rows['TotalTime'] into $totalTimeArr array for addition.
$graphArr[] should be updated (for array_sum($totalTimeArr)) first before push into array.
only one $graphArr[] for each machine
I now have problems regarding the third condition. It does not calculate first, instead it pushes the first data input. I have tried using do while loop, putting $graphArr[] = '["'.$rows['Machine#'].'",'.array_sum($totalTimeArr).']'; outside the if else loop, but this seems to be the closest I can get to what it's supposed to be. Other codes don't seem to have any problems and work well. Appreciate your recommendations/suggestions/assistance. Below is the code.
while ($rows = mysqli_fetch_array($conn))
{
if(!(in_array($rows['Machine#'], $machineArr)))
{
unset($totalTimeArr);
$machineArr[] = $rows['Machine#'];
$totalTimeArr[] = $rows['TotalTime'];
$graphArr[] = '["'.$rows['Machine#'].'",'.array_sum($totalTimeArr).']';
}
else if(in_array($rows['Machine#'], $machineArr))
{
$totalTimeArr[] = $rows['TotalTime'];
}
}
EDIT: I'm currently on this:
while ($rows = mysqli_fetch_array($conn))
{
$exists = false;
if( in_array($rows['Machine#'], $machineArr) )
{
$exists = true;
}
$totalTimeArr[] = $rows['TotalTime'];
if($exists === false)
{
$totalTimeArr = array();
$machineArr[] = $rows['Machine#'];
$totalTimeArr[] = $rows['TotalTime'];
}
$graphArr[] = '["'.current($machineArr).'",'.array_sum($totalTimeArr).']';
next($machineArr);
}
The result:
Array ( [0] => ["09CS1", 1.4]
[1] => ["08CS1", 1 ]
[2] => ["06CS1", 1 ]
[3] => ["" , 1.5]
[4] => ["02CS2", 1 ]
[5] => ["01CS2", 20 ]
[6] => ["" , 40 ]
[7] => ["01CS1", 1 ]
)
How do I remove ["", 1.5] and ["", 40]?
Below is the database:
I'm not sure what you need to do, if you need a running sum for a specific type of a machine then do something like:
$totalTileArr = [];
while ($rows = mysqli_fetch_array($conn)) {
if (!isset($totalTileArr[$rows['Machine#']])) {
$totalTileArr[$rows['Machine#']] = [];
}
$totalTimeArr[$rows['Machine#']][] = $rows['TotalTime'];
$graphArr[$rows['Machine#']] = '["' . $rows['Machine#'] . '",' . array_sum($totalTimeArr[$rows['Machine#']]) . ']';
}
A slightly modified version of your code cleaned up
$machineArr = Array();
while ($rows = mysqli_fetch_array($conn)) {
$exists = false;
if( in_array($rows['Machine#'], $machineArr) ) { $exists = true; }
$totalTimeArr[] = $rows['TotalTime'];
if($exists === false) {
unset($totalTimeArr);
$machineArr[] = $rows['Machine#'];
$totalTimeArr[] = $rows['TotalTime'];
$graphArr[] = '["'.$rows['Machine#'].'",'.array_sum($totalTimeArr).']';
}
}
Converted the check into one in_array() search, then comparing using === bitwise operator to evaluate the condition. Also defined $machineArr as an Array() as the first check in your loop would always fail given that $machineArr was (presumably as I don't see the code prior to the while loop) undefined.

How to count the total in array from within a multidimensional array

I have an array which comes from a report.
This report has info similar to:
157479877294,OBSOLETE_ORDER,obelisk,19/01/2013 01:42pm
191532426695,WRONG_PERFORMANCE,g3t1,19/01/2013 01:56pm
159523681637,WRONG_PERFORMANCE,g3t1,19/01/2013 01:57pm
176481653889,WRONG_PERFORMANCE,g4t1,19/01/2013 01:57pm
167479810401,WRONG_PERFORMANCE,g4t1,19/01/2013 02:00pm
172485359309,WRONG_PERFORMANCE,g4t2,19/01/2013 02:02pm
125485358802,WRONG_PERFORMANCE,g4t2,19/01/2013 02:02pm
172485359309,DAY_LIMIT_EXCEEDED,obelisk,19/01/2013 02:03pm
125485358802,DAY_LIMIT_EXCEEDED,obelisk,19/01/2013 02:03pm
What I need to do is get the total of each type of error and the location so for the first would be error: 'OBSOLETE_ORDER' and location: 'obelisk'. I have tried to do this a number of ways but the best I can come up with is a multi dimensional array:
$error_handle = fopen("$reportUrl", "r");
while (!feof($error_handle) )
{
$line_of_text = fgetcsv($error_handle, 1024);
$errorName = $line_of_text[1];
$scannerName = $line_of_text[2];
if($errorName != "SCAN_RESULT" && $errorName != "" && $scannerName != "SCAN_LOGIN" && $scannerName != "")
{
$errorsArray["$errorName"]["$scannerName"]++;
}
}
fclose($error_handle);
print_r($errorsArray);
gives me the following:
Array ( [OBSOLETE_ORDER] => Array ( [obelisk] => 1 ) [WRONG_PERFORMANCE] => Array ( [g3t1] => 2 [g4t1] => 2 [g4t2] => 2 ) [DAY_LIMIT_EXCEEDED] => Array ( [obelisk] => 2 ) )
which is great...except how do I then take that apart to add to my sql database?! (I am interested in getting the key and total of that key under the key the array is under)
and then add it to the tables
-errors-
(index)id_errors
id_event
id_access_scanner
id_errors_type
total_errors
-errors_type-
(index)id_errors_type
name_errors_type
-access_scanner-
(index)id_access_scanner
id_portal
name_access_scanner
PLEASE HELP!
Thanks!
A multidimensional array is more than you need. The approach to take is to create your own string ($arrayKey in my example) to use as an array key that combines the scanner name and the error so that you can get a count.
//this is the array containing all the report lines, each as an array
$lines_of_text;
//this is going to be our output array
$errorScannerArray = array();
//this variable holds the array key that we're going to generate from each line
$arrayKey = null;
foreach($lines_of_text as $line_of_text)
{
//the array key is a combination of the scanner name and the error name
//the tilde is included to attempt to prevent possible (rare) collisions
$arrayKey = trim($line_of_text[1]).'~'.trim($line_of_text[2]);
//if the array key exists, increase the count by 1
//if it doesn't exist, set the count to 1
if(array_key_exists($arrayKey, $errorScannerArray))
{
$errorScannerArray[$arrayKey]++;
}
else
{
$errorScannerArray[$arrayKey] = 1;
}
}
//clean up
unset($line_of_text);
unset($arrayKey);
unset($lines_of_text);
//displaying the result
foreach($errorScannerArray as $errorScanner => $count)
{
//we can explode the string hash to get the separate error and scanner names
$names = explode('~', $errorScanner);
$errorName = $names[0];
$scannerName = $names[1];
echo 'Scanner '.$scannerName.' experienced error '.$errorName.' '.$count.' times'."\n";
}
$list = array();
foreach ($lines as $line) {
$values = explode(',' $line);
$error = $values[1];
$scanner = $values[2];
if (!isset($list[$error])) {
$list[$error] = array();
}
if (!isset($list[$error][$scanner])) {
$list[$error][$scanner] = 1;
} else {
$list[$error][$scanner]++;
}
}
To go through each result I just did the following:
foreach ($errorsArray as $errorName=>$info)
{
foreach ($info as $scannerName=>$total)
{
print "$errorName -> $scannerName = $total </br>";
}
}
and now will just connect it to the sql
With your edited question, this much simpler loop will work for you, you just need to then insert the data into your database inside the loop, instead of echoing it out:
$errorsArray = Array (
[OBSOLETE_ORDER] => Array (
[obelisk] => 1
)
[WRONG_PERFORMANCE] => Array (
[g3t1] => 2
[g4t1] => 2
[g4t2] => 2
)
[DAY_LIMIT_EXCEEDED] => Array (
[obelisk] => 2
)
)
foreach($errorsArray as $row => $errors) {
foreach($errors as $error => $count) {
echo $row; // 'OBSOLETE_ORDER'
echo $error; // 'obelisk'
echo $count; // 1
// insert into database here
}
}
OLD ANSWER
You just need a new array to hold the information you need, ideally a count.
Im assuming that the correct data format is:
$report = [
['157479877294','OBSOLETE_ORDER','obelisk','19/01/2013 01:42pm'],
['191532426695','WRONG_PERFORMANCE','g3t1','19/01/2013 01:56pm'],
['159523681637','WRONG_PERFORMANCE','g3t1','19/01/2013 01:57pm'],
['176481653889','WRONG_PERFORMANCE','g4t1','19/01/2013 01:57pm'],
.....
];
foreach($report as $array) {
$errorName = $array[1];
$scannerName = $array[2];
if(exists($errorsArray[$errorName][$scannerName])) {
$errorsArray[$errorName][$scannerName] = $errorsArray[$errorName][$scannerName] + 1;
}
else {
$errorsArray[$errorName][$scannerName] = 1;
}
}

how to merge keys with same value?

code;
$all_tags = array();
while ($row = mysql_fetch_assoc($result)) {
$all_tags = array_merge($all_tags, explode(' ', $row['title']));
}
$all_tags = array_count_values($all_tags);
echo "<pre>";
arsort($all_tags);
foreach ($all_tags as $key => $val) {
echo "$key = $val\n";
}
output;
fuups! = 7
401 = 5
Authorization = 5
Required = 5
, = 3
izle = 3
Error = 2
Server = 2
Internal = 2
500 = 2
Full = 1
MegaSinema.net = 1
Sinema = 1
Bad = 1
Request = 1
Film = 1
400 = 1
all i wanna do is merge 'keys' with same integer 'value'. example;
401 = 5
Authorization = 5
Required = 5
to
401 Authorization Required = 5
i don't know how could i do it. i tried a bunch of ways but i never let it work. thank you.
I misunderstood you in the beginning.
I think you could just save the objects in an array and implode them if needed.
$out = array();
foreach($array as $key=>$value)
if(array_key_exists($value, $out))
$out[$value][] = $key;
else
$out[$value] = array($key);
// Then you could do
echo implode(" ", $out[5]); // Should output "401 Authorization Required"
Working example at http://codepad.org/MgLKXA75
Another option is to directly append it and trim the "extra" space at the end.
$out = array();
foreach($array as $key=>$value)
if(array_key_exists($value, $out))
$out[$value] .= $key . ' ';
else
$out[$value] = $key . ' ';
// Then you could do
echo trim($out[5]); // Should output "401 Authorization Required"
Try this
<?php
$data = array('fuups!' => '7','401' => '5','Authorization' => '5','Required' => '5',',' => '3','izle' => '3','Error' => '2','Server' => '2','Internal' => '2','500' => '2','Full' => '1','MegaSinema.net' => '1','Sinema' => '1','Bad' => '1','Request' => '1','Film' => '1','400' => '1');
$rows = array();
$values = array_values($data);
asort($values);
$highestVal = $values[0];
for ($i = 0; $i <= $highestVal; $i++) {
foreach ($data as $key => $value) {
if ($i == $value) {
$rows[$i] = $rows[$i] . " {$key}";
}
}
}
?>
Working Example XD http://codepad.org/x9uHs1sp
EDIT----
To echo all keys, just replace var_dump($rows) with:
foreach ($rows as $key) {
echo "{$key}<br />";
}
I'm not familiar with PHP, but I think you can try to create a hash table to handle this.
For example, if you insert above 3 items into the hash table and use '5' as the key, the first item can be inserted correctly, and the other two should throw exceptions. You can catch the exception since it's excepted and append the values to the value of the first item. So the item in you hash table should be like:
key: 5
value: 401 Authorization Required
But you should make sure about the orders in the value.
Just my 2 cents, good luck!
Update:
If throwing exception is not acceptable, you can look-up a key in the hash table first, if the key doesn't exist then insert the key and value, if it already exists then append the value to existing item value.

How do I redistribute an array into another array of a certain "shape". PHP

I have an array of my inventory (ITEMS A & B)
Items A & B are sold as sets of 1 x A & 2 x B.
The items also have various properties which don't affect how they are distributed into sets.
For example:
$inventory=array(
array("A","PINK"),
array("A","MAUVE"),
array("A","ORANGE"),
array("A","GREY"),
array("B","RED"),
array("B","BLUE"),
array("B","YELLOW"),
array("B","GREEN"),
array("B","BLACK")
);
I want to redistribute the array $inventory to create $set(s) such that
$set[0] => Array
(
[0] => array(A,PINK)
[1] => array(B,RED)
[2] => array(B,BLUE)
)
$set[1] => Array
(
[0] => array(A,MAUVE)
[1] => array(B,YELLOW)
[2] => array(B,GREEN)
)
$set[2] => Array
(
[0] => array(A,ORANGE)
[1] => array(B,BLACK)
[2] => NULL
)
$set[3] => Array
(
[0] => array(A,GREY)
[1] => NULL
[2] => NULL
)
As you can see. The items are redistributed in the order in which they appear in the inventory to create a set of 1 x A & 2 x B. The colour doesn't matter when creating the set. But I need to be able to find out what colour went into which set after the $set array is created. Sets are created until all inventory is exhausted. Where an inventory item doesn't exist to go into a set, a NULL value is inserted.
Thanks in advance!
I've assumed that all A's come before all B's:
$inventory=array(
array("A","PINK"),
array("A","MAUVE"),
array("A","ORANGE"),
array("A","GREY"),
array("B","RED"),
array("B","BLUE"),
array("B","YELLOW"),
array("B","GREEN"),
array("B","BLACK")
);
for($b_start_index = 0;$b_start_index<count($inventory);$b_start_index++) {
if($inventory[$b_start_index][0] == 'B') {
break;
}
}
$set = array();
for($i=0,$j=$b_start_index;$i!=$b_start_index;$i++,$j+=2) {
isset($inventory[$j])?$temp1=$inventory[$j]:$temp1 = null;
isset($inventory[$j+1])?$temp2=$inventory[$j+1]:$temp2 = null;
$set[] = array( $inventory[$i], $temp1, $temp2);
}
To make it easier to use your array, you should make it something like this
$inv['A'] = array(
'PINK',
'MAUVE',
'ORANGE',
'GREY'
);
$inv['B'] = array(
'RED',
'BLUE',
'YELLOW',
'GREEN',
'BLACK'
);
This way you can loop through them separately.
$createdSets = $setsRecord = $bTemp = array();
$bMarker = 1;
$aIndex = $bIndex = 0;
foreach($inv['A'] as $singles){
$bTemp[] = $singles;
$setsRecord[$singles][] = $aIndex;
for($i=$bIndex; $i < ($bMarker*2); ++$i) {
//echo $bIndex.' - '.($bMarker*2).'<br/>';
if(empty($inv['B'][$i])) {
$bTemp[] = 'null';
} else {
$bTemp[] = $inv['B'][$i];
$setsRecord[$inv['B'][$i]][] = $aIndex;
}
}
$createdSets[] = $bTemp;
$bTemp = array();
++$bMarker;
++$aIndex;
$bIndex = $bIndex + 2;
}
echo '<pre>';
print_r($createdSets);
print_r($setsRecord);
echo '</pre>';
To turn your array into an associative array, something like this can be done
<?php
$inventory=array(
array("A","PINK"),
array("A","MAUVE"),
array("A","ORANGE"),
array("A","GREY"),
array("B","RED"),
array("B","BLUE"),
array("B","YELLOW"),
array("B","GREEN"),
array("B","BLACK")
);
$inv = array();
foreach($inventory as $item){
$inv[$item[0]][] = $item[1];
}
echo '<pre>';
print_r($inv);
echo '</pre>';
Maybe you can use this function, assuming that:
... $inventory is already sorted (all A come before B)
... $inventory is a numeric array staring at index zero
// $set is the collection to which the generated sets are appended
// $inventory is your inventory, see the assumptions above
// $aCount - the number of A elements in a set
// $bCount - the number of B elements in a set
function makeSets(array &$sets, array $inventory, $aCount, $bCount) {
// extract $aItems from $inventory and shorten $inventory by $aCount
$aItems = array_splice($inventory, 0, $aCount);
$bItems = array();
// iterate over $inventory until a B item is found
foreach($inventory as $index => $item) {
if($item[0] == 'B') {
// extract $bItems from $inventory and shorten $inventory by $bCount
// break out of foreach loop after that
$bItems = array_splice($inventory, $index, $bCount);
break;
}
}
// append $aItems and $bItems to $sets, padd this array with null if
// less then $aCount + $bCount added
$sets[] = array_pad(array_merge($aItems, $bItems), $aCount + $bCount, null);
// if there are still values left in $inventory, call 'makeSets' again
if(count($inventory) > 0) makeSets($sets, $inventory, $aCount, $bCount);
}
$sets = array();
makeSets($sets, $inventory, 1, 2);
print_r($sets);
Since you mentioned that you dont have that much experience with arrays, here are the links to the php documentation for the functions I used in the above code:
array_splice — Remove a portion of the array and replace it with something else
array_merge — Merge one or more arrays
array_pad — Pad array to the specified length with a value
This code sorts inventory without any assumption on inventory ordering. You can specify pattern (in $aPattern), and order is obeyed. It also fills lacking entries with given default value.
<?php
# config
$aInventory=array(
array("A","PINK"),
array("A","MAUVE"),
array("A","ORANGE"),
array("A","GREY"),
array("B","RED"),
array("B","BLUE"),
array("B","YELLOW"),
array("B","GREEN"),
array("B","BLACK"),
array("C","cRED"),
array("C","cBLUE"),
array("C","cYELLOW"),
array("C","cGREEN"),
array("C","cBLACK")
);
$aPattern = array('A','B','A','C');
$mDefault = null;
# preparation
$aCounter = array_count_values($aPattern);
$aCurrentCounter = $aCurrentIndex = array_fill_keys(array_unique($aPattern),0);
$aPositions = array();
$aFill = array();
foreach ($aPattern as $nPosition=>$sElement){
$aPositions[$sElement] = array_keys($aPattern, $sElement);
$aFill[$sElement] = array_fill_keys($aPositions[$sElement], $mDefault);
} // foreach
$nTotalLine = count ($aPattern);
$aResult = array();
# main loop
foreach ($aInventory as $aItem){
$sElement = $aItem[0];
$nNeed = $aCounter[$sElement];
$nHas = $aCurrentCounter[$sElement];
if ($nHas == $nNeed){
$aCurrentIndex[$sElement]++;
$aCurrentCounter[$sElement] = 1;
} else {
$aCurrentCounter[$sElement]++;
} // if
$nCurrentIndex = $aCurrentIndex[$sElement];
if (!isset($aResult[$nCurrentIndex])){
$aResult[$nCurrentIndex] = array();
} // if
$nCurrentPosition = $aPositions[$sElement][$aCurrentCounter[$sElement]-1];
$aResult[$nCurrentIndex][$nCurrentPosition] = $aItem;
} // foreach
foreach ($aResult as &$aLine){
if (count($aLine)<$nTotalLine){
foreach ($aPositions as $sElement=>$aElementPositions){
$nCurrentElements = count(array_keys($aLine,$sElement));
if ($aCounter[$sElement] != $nCurrentElements){
$aLine = $aLine + $aFill[$sElement];
} // if
} // foreach
} // if
ksort($aLine);
# add empty items here
} // foreach
# output
var_dump($aResult);
Generic solution that requires you to specify a pattern of the form
$pattern = array('A','B','B');
The output will be in
$result = array();
The code :
// Convert to associative array
$inv = array();
foreach($inventory as $item)
$inv[$item[0]][] = $item[1];
// Position counters : int -> int
$count = array_fill(0, count($pattern),0);
$out = 0; // Number of counters that are "out" == "too far"
// Progression
while($out < count($count))
{
$elem = array();
// Select and increment corresponding counter
foreach($pattern as $i => $pat)
{
$elem[] = $inv[ $pat ][ $count[$i]++ ];
if($count[$i] == count($inv[$pat]))
$out++;
}
$result[] = $elem;
}

Categories