Does Php Have Built-in Array Functions That Can Sort/assign Values For Boolean Result?
Solution 1:
This is a php function I wrote quickly that does what you want, I have quickly tested it and it seems to work properly.
<?php
function compare($orders){
if(sizeof($orders) == 0){
return 1;
}
$quantity = array();
foreach ($orders as $order) {
if(sizeof($order) == 0){
return 0;
}
foreach ($order as $employee) {
if(array_key_exists($employee, $quantity)){
$quantity[$employee]++;
}
else{
$quantity[$employee] = 1;
}
}
}
$chosenEmployees = array_keys($quantity, min($quantity));
$chosenEmployee = $chosenEmployees[0];
$length = array();
foreach ($orders as $key => $order) {
$length[$key] = sizeof($order);
}
for ($i=0; $i < sizeof($orders); $i++) {
$chosenOrders = array_keys($length, min($length));
foreach ($chosenOrders as $orderKey) {
if(in_array($chosenEmployee, $orders[$orderKey])){
unset($orders[$orderKey]);
foreach ($orders as $key1 => $order) {
foreach ($order as $key2 => $employee) {
if($employee == $chosenEmployee){
unset($orders[$key1][$key2]);
}
}
}
return compare($orders);
}
else{
unset($length[$orderKey]);
}
}
}
}
$out = compare($orders);
?>
To use it, type compare($your_array_name), and the function will return 0 (false) or 1 (true).
Hope it helps.
Edit:
I doubt you'll find this code anywhere else because I wrote it for this question.
I have been working on proof and can prove that when the function returns true, it is true.
The function returned true.
=> The orders array is empty.
=> Before that, the orders array contained one order that can be done by at least employee one.
=> Before that, the orders array contained two orders that can be done respectively by at least employee one and employee two.
Via recurrence, we can deduce that n steps before the end, there were n orders, all doeable by at least one unique employee.
If n = size of initial array, we can conclude that if the function returns true, it is correct.
If this proof is not correct, please let me know. I will edit my post again if I find proof for the second half.
Solution 2:
One solution is to use array_reduce
and array_diff
to speculatively assign employees to orders.
//Each step tries to add another employee id to the $carry array
function calc($carry, $item)
{
if (!$carry) {
$carry = array();
}
$diff = array_diff($item, $carry);
if (count($diff) > 0) {
array_push($carry, reset($diff));
}
return $carry;
}
function cmp($a, $b)
{
return count($a) - count($b);
}
function checkCondition($arrayToCheck)
{
uasort($arrayToCheck, 'cmp');
$reduced = array_reduce($arrayToCheck, "calc");
//If we have a shorter array than the number of orders, we have a problem
return count($reduced) == count($arrayToCheck);
}
$o = array(
array(0,1,2),
array(0,1,2),
array(3),
array(3),
);
$result = checkCondition($o);
echo $result + " " + $result ? "Good" : "Bad"; //Should be Bad
$o = array(
array(0,1,2),
array(0,1,2),
array(1),
array(3),
);
$result = checkCondition($o);
echo $result + " " + $result ? "Good" : "Bad"; //Should be Good
Sorting the array first avoids the problem of "assigning" a worker to an order who MUST be assigned to a later order.
Solution 3:
Algorithm
Your main issue is about the algorithm. As discussed, the language is of secondary importance.
What you want is to
check if each order can be assigned one employee and each employee assigned one or no order
You can draw it like a graph:
- nodes are orders and employees
- links are possible assignments
So you want to remove all necessary links so that
- each employee node has one or no link left, and
- each order node still has one (or more) link left
If you succeed, you have a solution and want the algorithm to return true
. Otherwise, it should return false
.
EDIT: J. Quick found an incredibly simple implementation that works. I would love to get a proof of it or a reference of where he found it though.
So I explain it here:
- If orders is empty, return
true
- If any order of orders has no employee, return
false
- Get employee e with least number of orders
- Get e's order o with least number of employees
- Remove e and o from orders
- Repeat from 1.
JavaScript implementation
function areAllOrdersFulfilled(orders) {
while (orders.length !== 0) {
if (undefined !== orders.find( o => o.length === 0))
// An order has no employee to fulfill it
return false;
// Get employee and order to remove
let employees = [];
orders.forEach( order => {
order.forEach( employee => {
employees[employee] = (employees[employee] || 0) + 1;
});
});
let employeeToRemove = employees.indexOf(employees.slice().sort()[0]), // Employee with less orders
orderToRemove = orders
.sort( (o1, o2) => o1.length - o2.length ) // In-place sort orders
.findIndex( o => o.includes(employeeToRemove)); // Order with less employees
// Remove
orders.splice(orderToRemove,1);
orders = orders.map( o => o.filter(e => e !== employeeToRemove) )
}
return true;
}
You can run it like that:
const orders = [
[0,1,2],
[0,1,2],
[3],
[3]
];
console.log(areAllOrdersFulfilled(orders));
Post a Comment for "Does Php Have Built-in Array Functions That Can Sort/assign Values For Boolean Result?"