【问题标题】:Compare array with duplicate values using array_intersect?使用array_intersect将数组与重复值进行比较?
【发布时间】:2012-10-07 13:05:34
【问题描述】:

我正在为我的目录设计一个包引擎。在这里,您可以将一定数量的产品添加到包装中并享受折扣。当您订购产品时,脚本必须检测哪些套餐交易适用于您的订单。

这是我的代码:

// packages
$packages["package1"] = array(1,1,2);
$packages["package2"] = array(1,2);

//orderlist
$orderlist = array(1,1,2,1,2,2);

// put the order list in a temp array
$temp_product_array = $orderlist;

foreach($packages as $pname => $package_array)
{
  $no_more_package = 0;
  do
  {
    // put the package products in a temp array
    $temp_package_array = $package_array;

    $is_packages_array = array_intersect($temp_package_array,$temp_product_array);

    // if all package values are present
    if(count($is_packages_array) == count($temp_package_array))
    {
      // add package name
      $packages_in_order[] =  $pname;

      // filter the package out of the product list but keep duplicate values
      foreach($temp_product_array as $key1 => $pid1)
      {
        foreach($temp_package_array as $key2 => $pid2)
        {
          if($pid1==$pid2)
          {
            unset($temp_product_array[$key1]);
            unset($temp_package_array[$key2]);
            break;  // after removing go to the next product to prevent double erasing
          }
        }
      }
    }
    else
    {
      $no_more_package = 1;
    }

  }
  while($no_more_package<1);
}

print_r($packages_in_order);
print_r($temp_product_array);

结果是:

Array ( [0] => package1 [1] => package1 ) Array ( [5] => 2 ) 

但我希望结果是:

Array ( [0] => package1 [1] => package2 ) Array ( [5] => 2 )

我尝试了array_diffarray_intersect,但它们都不能很好地处理重复值。

有没有人有更好/更有效的方法来解决这个问题?
(PS 由于来源不同,我无法使用关联数组)

【问题讨论】:

  • 所以 orderlist 必须包含与包裹相同的产品(并且顺序相同)才能匹配?
  • 订单列表以任何可能的顺序包含任意数量的商品 ID。 (在脚本中,包裹是按折扣订购的。)

标签: php arrays array-intersect


【解决方案1】:
// packages
$packages["package1"] = array(1,1,2);
$packages["package2"] = array(1,2);

//orderlist
$orderlist = array(1,1,1,2,2,2);



// put the order list in a temp array
$temp_product_array = $orderlist;
$product_count_array = array_count_values($temp_product_array);

foreach($packages as $pname => $temp_package_array)
{
  $no_more_package = 0;
  do
  {
    $test_package_array = array();

    foreach($temp_package_array as $key => $pid)
    {
      // check if the product is still in the order totals 
      if(isset($product_count_array[$pid]) && $product_count_array[$pid]>0)
       {
         $product_count_array[$pid]--;
         $test_package_array[] = $pid;
       }
       else
       {
         $no_more_package = 1;
       }
    }
    // check if the found products match the package count
    if(count($temp_package_array)==count($test_package_array))
    {
      $packages_in_order[] = $pname;
    }
    else
    {
      // add the extracted products in case of incomplete package 
      foreach($test_package_array as $pid)
       {
         $product_count_array[$pid]++;
       }
    }


  }
  while($no_more_package<1);
}

print_r($packages_in_order);
print_r($product_count_array);

【讨论】:

    【解决方案2】:

    我会解决这个问题。其中一部分是在列表中找到包。在一个可能相关的问题中,一个完全执行此操作的现有函数被命名为 consecutive_valuesSearching for consecutive values in an array

    可以在另一个数组中以确切的顺序定位一个数组。这可能就是你想要的。

    剩下的部分是搜索包然后非常简单。如果您正确理解了您的问题,那么您也希望返回剩余的内容:

    list($found, $rest) = find_packages($packages, $orderlist);
    var_dump($found, $rest);
    
    function find_packages(array $packages, array $list)
    {
        $found = array();
        foreach($packages as $name => $package) {
            # consecutive_values() is @link https://stackoverflow.com/a/6300893/367456
            $has = consecutive_values($package, $list);
            if ($has === -1) continue;
            $found[] = $name;
            array_splice($list, $has, count($package));
        }
    
        return array($found, $list);
    }
    

    输出:

    array(2) {
      [0] =>
      string(8) "package1"
      [1] =>
      string(8) "package2"
    }
    array(1) {
      [0] =>
      int(2)
    }
    

    编辑: 多次搜索同一个包需要稍作修改。这里创建了一个内部 while 循环,如果找不到当前包,则需要中断:

    function find_packages(array $packages, array $list)
    {
        $found = array();
        foreach($packages as $name => $package) {
            while (true) {
                # consecutive_values() is @link https://stackoverflow.com/a/6300893/367456
                $has = consecutive_values($package, $list);
                if ($has === -1) break;
                $found[] = $name;
                array_splice($list, $has, count($package));
            }
        }
    
        return array($found, $list);
    }
    

    【讨论】:

    • 这非常有效。我会用更多的包和产品创意来测试它。谢谢!!
    • 大约在同一时刻,我也经历了一次突破。我将发布我的解决方案。好奇解决这个问题的最佳方法..
    • 我总是将问题分解为函数。该代码更易于遵循和更改。你也可以很容易地测试它们正常工作的叶子函数。
    • 这个方案还是有问题的。如果我更改包装顺序,结果应该是: Array ( [0] => package1 [1] => package1 [2] => package1 ) Array ( [1] => 0 [2] => 0 ) 但是这个解决方案给出: array(2) { [0]=> string(8) "package1" [1]=> string(8) "package2" } array(1) { [0]=> int(2) }
    • 啊,好吧,你想多次查看同一个包,我不清楚。有点小改动,我加了一点解释一下。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-12-24
    • 2014-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多