1

在 Microsoft Dynamics Nav 2013 中,有一个功能可以为项目(产品)指定项目替换;但是,您可以为单个产品指定多个替换,并且从技术上讲,替换本身可以具有一个或多个替换。

我正在尝试在 PHP 中构建一个递归解决方案,它允许我获取已知的产品代码,并递归搜索项目替换以生成一维项目数组。如果这是一对一的关系(父母,孩子),这对我来说将是一项微不足道的任务,但是在任何给定的迭代中都可以有多个孩子的事实让我大吃一惊。

我的问题是,是否有人知道如何为我上面描述的情况编写递归方法?下面我将布局数据的结构方式,以便更好地理解问题:

$lineItems = array(
    'XXX-0',
    'XXX-1',
    'XXX-3'
);

$substitutionsLookup = array(
    0 => array('No_' => 'XXX-1', 'Substitute No_' => 'XXX-2'),
    1 => array('No_' => 'XXX-3', 'Substitute No_' => 'XXX-4'),
    2 => array('No_' => 'XXX-3', 'Substitute No_' => 'XXX-5'),
    3 => array('No_' => 'XXX-5', 'Substitute No_' => 'XXX-6')
);

// Resulting product code substitutions for XXX-0
$result1 = array();

// Resulting product code substitutions for XXX-1
$result2 = array('XXX-2');

// Resulting product code substitutions for XXX-3
$result3 = array('XXX-4', 'XXX-6');

编辑(添加了我使用递归方法解决的尝试):

protected function getSubstitutions($haystack, $needle, &$results = array())
{
    if (count($haystack) == 0)
    {
        return false;
    }

    $matches = array();   
    foreach ($haystack as $index => $check)
    {
        if ($check['No_'] === $needle)
        {
            $newHaystack = $haystack;
            unset($newHaystack[$index]);

            $moreMatches = $this->getSubstitutions($newHaystack, $check['Substitute No_'], $results);

            if ($moreMatches === false)
            {
                $matches[] = $check['Substitute No_'];
            }
        }
    }

    if (count($matches))
    {
        foreach($matches as $match)
        {
            $results[] = $match;
        }
    }

    return $results;
}

编辑(使用的最终代码,来自接受的答案):

class ItemSubstitutionService implements ServiceLocatorAwareInterface
{    
    public function getSubstitutions($itemNo, $noInventoryFilter = true, $recursive = true)
    {
        $substitutions = array();
        $directSubs = $this->itemSubstitutionTable->getSubstitutionsByNo($itemNo);

        if ($recursive)
        {
            foreach($directSubs as $sub)
            {
                $this->getSubstitutionsRecursive($sub, $substitutions);
            }
        } else {
            $substitutions = $directSubs;
        }

        foreach($substitutions as $index => $sub)
        {
            $inventory = $this->itemLedgerEntryTable->getQuantityOnHand($sub->getSubstituteNo());
            $sub->setInventory($inventory);

            if ($noInventoryFilter)
            {
                if ($inventory == 0)
                {
                    unset($substitutions[$index]);
                }
            }
        }

        return $substitutions;
    }

    private function getSubstitutionsRecursive(ItemSubstitution $sub, &$subs)
    {
        $directSubs = $this->itemSubstitutionTable->getSubstitutionsByNo($sub->getSubstituteNo());
        if (empty($directSubs))
        {
            $subs[$sub->getSubstituteNo()] = $sub;
        }

        foreach($directSubs as $curSub)
        {
            $this->getSubstitutionsRecursive($curSub, $subs);
        }
    }
}
4

1 回答 1

1

此代码可以作为您的示例的解决方案。我只是假设您从数据库中获取“直接”项目替代品列表,因此您可以将 GetDirectSubstitutes 替换为获取给定项目的替代品列表的代码(我使用您的示例数组作为数据源)。

请注意——这个简单的实现不会检查循环引用。如果您的初始数据包含循环,则此代码将卡住。

function GetDirectSubstitutes($itemNo)
{
    global $substitutionsLookup;
    $items = array();
    foreach ($substitutionsLookup as $itemPair) {
        if ($itemPair['No'] == $itemNo) {
            array_push($items, $itemPair['SubstNo']);
        }
    }

    return $items;
}

function GetSubstitutesTree($itemNo, &$substitutes)
{
    $directSubst = GetDirectSubstitutes($itemNo);
    if (!empty($directSubst)) {
        $substitutes = array_merge($substitutes, $directSubst);
        foreach ($directSubst as $item) {
            GetSubstitutesTree($item, $substitutes);
        }
    }
}
于 2014-12-18T21:46:53.600 回答