PHP:如何确保数组包含所有值的组合


PHP: How to ensure, an array contains all combinations of values

好了,问题来了:我有一个结构如下的数组:

$array[0] 'fruit' -> 'apple', 'origin' -> 'usa', 'price' -> '$1'
$array[1] 'fruit' -> 'apple', 'origin' -> 'canada', 'price' -> '$1'
$array[2] 'fruit' -> 'pear', 'origin' -> 'usa', 'price' -> '$1'
$array[3] 'fruit' -> 'peach', 'origin' -> 'spain', 'price' -> '$2'
$array[4] 'fruit' -> 'peach', 'origin' -> 'greece', 'price' -> '$0.5'

这个数组包含了很多水果,它们有很多不同的起源。我们的目标是,确保每个水果都有所有可能的(= all in the array contained origins)来源。如果其中一个组合缺失,则应将一条新记录添加到具有'price' -> 'tba'的数组中。

因此,在上面的例子中,有三种不同的水果(apple, pear, peach)和四种不同的起源(usa, canada, spain, greece)

我需要检查每个水果是否有所有可能的来源,如果没有,将它们与tba价格相加。

如何解决这个in a performant way ?我已经尝试使用只包含起源和水果的额外数组,但到目前为止还没有运气。

编辑:这是预期的结果(排序目前不是那么重要):

$array[0] 'fruit' -> 'apple', 'origin' -> 'usa', 'price' -> '$1'
$array[1] 'fruit' -> 'apple', 'origin' -> 'canada', 'price' -> '$1'
$array[2] 'fruit' -> 'apple', 'origin' -> 'spain', 'price' -> 'tba'
$array[3] 'fruit' -> 'apple', 'origin' -> 'greece', 'price' -> 'tba'
$array[4] 'fruit' -> 'pear', 'origin' -> 'usa', 'price' -> '$1'
$array[5] 'fruit' -> 'pear', 'origin' -> 'canada', 'price' -> 'tba'
$array[6] 'fruit' -> 'pear', 'origin' -> 'spain', 'price' -> 'tba'
$array[7] 'fruit' -> 'pear', 'origin' -> 'greece', 'price' -> 'tba'
$array[8] 'fruit' -> 'peach', 'origin' -> 'usa', 'price' -> 'tba'
$array[9] 'fruit' -> 'peach', 'origin' -> 'canada', 'price' -> 'tba'
$array[10] 'fruit' -> 'peach', 'origin' -> 'spain', 'price' -> '$2'
$array[11] 'fruit' -> 'peach', 'origin' -> 'greece', 'price' -> '$0.5'

我尝试到目前为止,但没有工作,因为a)错误与变量,和b)超时30已达到:

$fruits = array('apple', 'pear', 'peach');
$origins = array('usa', 'canada', 'spain', 'greece');

然后我尝试遍历主数组并检查每个组合:

foreach ($fruits as $f)
{
   foreach ($origins as $o)
   {
      if (!current(array_filter($array, function($item) { return $f == $item['fruit'] && $o == $item['origin']; }));)
      {
          // add the fruit-origin combination the the main array
      }
   }
}

这不起作用,因为$f和$o在函数中不可用。

我不知道您是如何使用这个列表的,但是您可能想要从特定的来源获得特定水果的价格,而不必每次都遍历整个数组。

对于这种情况,使用不同的数组格式是一个好主意。您可以像这样生成它:
<?php
$produceList = [
    ['fruit' => 'apple', 'origin' => 'usa',    'price' => '$1'],
    ['fruit' => 'apple', 'origin' => 'canada', 'price' => '$1'],
    ['fruit' => 'pear',  'origin' => 'usa',    'price' => '$1'],
    ['fruit' => 'peach', 'origin' => 'spain',  'price' => '$2'],
    ['fruit' => 'peach', 'origin' => 'greece', 'price' => '$0.5'],
];
$newProduceList = array();
foreach ($produceList as $product) {
    $newProduceList[$product['fruit']][$product['origin']] = $product['price'];
}

这将给你一个数组,你可以使用水果和起源作为索引:

Array(
    [apple] => Array(
            [usa] => $1
            [canada] => $1
    )
    [pear] => Array(
            [usa] => $1
    )
    [peach] => Array(
            [spain] => $2
            [greece] => $0.5
    )
)

这样很容易得到产品的具体价格:

<?php
if (isset($newProduceList['apple']['germany'])) {
    echo $newProduceList['apple']['germany'];
} else {
    echo 'tba';
}
// Output: tba

如果在这段代码周围添加一个函数作为包装器,那么就可以使用"getProducePrice('apple', 'canada');"来返回价格或"tba"。

<?php
function getProducePrice($fruit, $origin) {
    global $newProduceList; // it's bad style to use globals, used just as example
    if (isset($newProduceList[$fruit][$origin])) {
        return $newProduceList[$fruit][$origin];
    } else {
        return 'tba';
    }
}
echo getProducePrice('pear', 'usa');
// Output: $1

使用原始数组

如果你被原来的数组格式卡住了,你总是需要遍历数组来搜索一个特定的水果,像这样:

<?php
$price = 'tba';
foreach ($produceList as $produce) {
    if ($produce['fruit']!='peach' || $produce['origin']!='spain') continue;
    // found the specific fruit from the specific origin
    $price = $produce['price'];
    break; // stop iterating through the rest of the array.
}
echo $price;
// Output: $2

看起来我找到了解决方案:

if (!current(array_filter($array, function($item) use($f, $o) { return $f == $item['fruit'] && $o == $item['origin']; }));)
      {
          // add the fruit-origin combination the the main array
      }

我错过了use($f, $o)部分。我不确定这是否可以调整性能,但目前我想它已经足够好了。然而,改进总是受欢迎的:)