使用array_intersect比较具有重复值的数组?

时间:2022-02-05 12:15:44

I'm designing a package engine for my catalog. Here you can add a certain ammount of products to the package and a discount. When you order products the script have to detect which package deals apply to your order.

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

Here is my code:

这是我的代码:

// 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);

The result is:

结果是:

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

But I want the result to be:

但我希望结果如下:

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

I tried array_diff, array_intersect but they all do not work well with duplicate values.

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

Does anyone has a better/working way of solving this?
(PS because of different sources I cannot work with associative arrays)

有没有人有更好/更有效的解决方法? (PS因为不同的来源我无法使用关联数组)

2 个解决方案

#1


0  

// 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


0  

I would devide the problem. Part of it is to locate the package inside the list. An existing function that does exactly that has been named consecutive_values in a probably related question: Searching for consecutive values in an array.

我会解决这个问题。部分原因是在列表中找到包。在一个可能相关的问题中确实命名为consecutive_values的现有函数:在数组中搜索连续值。

With it is it possible to locate an array within another array in the exact order. This is probably what you want.

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

The part left is to search for the packages then and is pretty straight forward. If you understood your question right, you want to return left-overs as well:

剩下的部分是搜索包然后非常直接。如果你理解你的问题,你也想要留下遗留问题:

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://*.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);
}

Output:

输出:

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

Edit: Searching for the same package multiple times needs a slight modification. Here the an inner while loop is created that needs a break if the current package is not found:

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

function find_packages(array $packages, array $list)
{
    $found = array();
    foreach($packages as $name => $package) {
        while (true) {
            # consecutive_values() is @link https://*.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);
}

#1


0  

// 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


0  

I would devide the problem. Part of it is to locate the package inside the list. An existing function that does exactly that has been named consecutive_values in a probably related question: Searching for consecutive values in an array.

我会解决这个问题。部分原因是在列表中找到包。在一个可能相关的问题中确实命名为consecutive_values的现有函数:在数组中搜索连续值。

With it is it possible to locate an array within another array in the exact order. This is probably what you want.

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

The part left is to search for the packages then and is pretty straight forward. If you understood your question right, you want to return left-overs as well:

剩下的部分是搜索包然后非常直接。如果你理解你的问题,你也想要留下遗留问题:

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://*.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);
}

Output:

输出:

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

Edit: Searching for the same package multiple times needs a slight modification. Here the an inner while loop is created that needs a break if the current package is not found:

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

function find_packages(array $packages, array $list)
{
    $found = array();
    foreach($packages as $name => $package) {
        while (true) {
            # consecutive_values() is @link https://*.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);
}