代码之家  ›  专栏  ›  技术社区  ›  Kragalon

如何从PHP数组中获取唯一和最流行的值

  •  2
  • Kragalon  · 技术社区  · 10 年前

    我试图从每个数组中获得最流行和唯一的值。我已经有了计算数组中这些对象点数的方法。将前3个数组视为“类别”: (显然是示例项)

    $item1 = array( spoon => 5, knife => 3, fork => 2); 
    $item2 = array( fork => 5, knife => 4, spoon => 2);
    $item3 = array( spoon => 4, knife => 3, fork => 1);
    

    这是每个类别的统计数据。然后,我为每个类别创建一个key_array,另一个数组由每个类别中最流行的元素组成。

    $max1 = array_keys($item1);
    $max2 = array_keys($item2);
    $max3 = array_keys($item3);
    
    $maxset = array( 0 => $max1[0], 1 => $max2[0], 2 => $max3[0]);
    

    举个例子,我有两个勺子 $maxset 。所以现在,我需要检查重复项并选择更流行的项:

        foreach($maxset as $key => $value){
            $check = array();                                 
            if(in_array($value, $check)){
                $checkkey = array_search($value, $check);     //get key where $value already exists
                $checkval = ${'item' . $checkkey+1}[$value];  // get popularity of original copy
                $checkvalnew = ${'item' . $key+1}[$value];    // get popularity of duplicate
    
                if ($checkval > $checkvalnew){                // if the original is more popular
                    $newvalue = ?;                    // ! 
                    array_push($check, $newvalue);      
                }                   
                else{                                         // if the duplicate is more popular
                    $check[$checkkey] = ?;            // !
                    array_push($check, $value);
                }
            }else{
                array_push($check, $value);
            }
        }
    

    如果它有 '// !' 我不知道在这里做什么。如果我得到一个新值,那么如果它也是一个重复值呢?我需要一个函数来检查它,但是我怎么才能不陷入循环呢?

    最后,它应该看起来像:

    $check = array(0 => spoon, 1 => fork, 2 => knife); // it would be inserted into a database
    

    我用了错误的方法来实现这一点吗?也许有一种更有效的语言来完成这项任务吗?谢谢你的帮助!

    编辑: (确定公式的其他示例集)**应选择答案的位置

    $item1 = array(red => 5, **green** => 4, yellow => 2, blue => 1);
    $item2 = array(**blue** => 5, green => 3, red => 2, yelow => 1);
    $item3 = array(**red** => 6, blue => 4, yellow => 2, green => 1);
    
    $check = array(0 => green, 1 => blue, 2 => red)  // red1 got replaced by more popular red3
    //Total point: 15
    
    
    $item1 = array(yellow => 5, blue => 4, **red** => 2, green => 1);
    $item2 = array(**blue** => 5, green => 3, red => 2, yellow => 1);
    $item3 = array(**yellow** => 6, green => 4, red => 2, blue => 1);
    
    $check = array(0 => red, 1 => blue, 2 => yellow)  // yellow1 got replaced by more popular yellow3. The replacement for yellow1 was blue1, which lost to blue2. 
    //Total point: 13
    
    3 回复  |  直到 10 年前
        1
  •  2
  •   Eugen Rieck    10 年前

    我们有两个不同的步骤:

    • 按流行程度排序
    • 保持唯一性

    让我们这样解决吧!

    //Step 1: Sort by popularity and dismiss values
    arsort($item1, SORT_NUMERIC);
    $item1=array_keys($item1);
    arsort($item2, SORT_NUMERIC);
    $item2=array_keys($item2);
    arsort($item3, SORT_NUMERIC);
    $item3=array_keys($item3);
    
    //Step 2: Keep unique
    //2a: $item1 has highest priority
    $maxset=array($item1[0]);
    //2b: Walk $item2 until we find an unused value
    foreach ($item2 as $item)
      if (!in_array($item, $maxset)) {
        $maxset[]=$item;
        break;
      }
    //2c: Walk $item3 until we find an unused value
    foreach ($item3 as $item)
      if (!in_array($item, $maxset)) {
        $maxset[]=$item;
        break;
      }
    

    经过评论中的讨论,问题的答案是不同的。下面是一个经过调整的解决方案:

    //Step 1: Collaps the three items into one array
    $maxset=array()
    foreach ($item1 as $k=>$v)
      if (!isset($maxset[$k])) 
        $maxset[$k]=$v;
      //Uncomment one of the following lines, depending
      //on whether you want sum or max of popularity
      // else if ($maxset[$k]<$v) $maxset[$k]=$v;
      // else $maxset[$k]+=$v;
    
    
    //Step 2: Sort by popularity and dismiss values
    arsort($maxset, SORT_NUMERIC);
    $maxset=array_keys($maxset);
    
    //Step 3: Cut to three items
    $maxset=array_slice($maxset, 0, 3);
    
        2
  •  1
  •   Eugen Rieck    10 年前

    开始一个新的答案,因为OQ已经发生了很大的变化。

    你现在要做的是考虑 $item1 , $item2 $item3 不是分层的,而是平等的-你从 任何 $itemX ,然后忽略此类别和值,重复两次。所以让我们这样做吧!

    第一步:我们需要一个函数,它在2D结构中找到最大值,然后从结构中删除找到它的行和列,给出后面的行和行。

    function reduce(&$items) {
    
        //Find max value and coordinates
        $item=false;
        $key=false;
        $value=0;
        foreach ($items as $i=>$a)
            foreach ($a as $k=>$v)
                if ($v>$value) {
                    $item=$i;
                    $key=$k;
                    $value=$v;
                }
    
        //Unset used coordinates
        unset($items[$item]);
        foreach ($items as $i=>$a)
            if (isset($a[$key])) unset($items[$i][$key]);
    
        //return found item
        return array($item, $key);
    }
    

    第二步:初始化所有内容并调用函数三次,然后清理

    $items=array($item1, $item2, $item3);
    $maxset=array();
    
    $reduce=reduce($items);
    $maxset[$reduce[0]]=$reduce[1];
    $reduce=reduce($items);
    $maxset[$reduce[0]]=$reduce[1];
    $reduce=reduce($items);
    $maxset[$reduce[0]]=$reduce[1];
    
    ksort($maxset);
    print_r($maxset);
    

    这一点已通过您的所有示例进行了验证。

        3
  •  -1
  •   Eliel    10 年前

    我不得不用以下内容替换我的全部答案。这是否接近您想要实现的目标?

    采取的步骤

    1. 创建我们的阵列
    2. 将我们的数组合并为一个,这样我们就可以轻松地遍历它
    3. 合并我们的数组并获得一组唯一的键(例如红色、绿色、黄色、蓝色、橙色)
    4. 循环遍历我们的巨型数组并分别访问它们(例如,item1、item2、item3)
    5. 将我们的点分类到一个列表中,该列表专门针对该类别/颜色(例如红色=>5、2、6)
    6. 获取该类别中最高或最受欢迎的数字,并将其放入我们的 $check 大堆
    7. 我们的 $支票 数组现在应该保存每个类别的最高值
    8. 使用 array_sum 以获得总点数。

      // Our arrays - notice i placed orange just to show how all the keys are merged
      
      $item1 = array('red' => 5, 'green' => 4, 'yellow' => 2, 'blue' => 1);
      $item2 = array('blue' => 5, 'green' => 3, 'red' => 2, 'yellow' => 1);
      $item3 = array('red' => 6, 'blue' => 4, 'yellow' => 2, 'green' => 1, 'orange' => 1);
      
      $items = array();
      $final = array();
      
      $items[] = $item1;
      $items[] = $item2;
      $items[] = $item3;
      
      // Grab a list of keys from our multiple arrays
      $item_keys = array_keys(array_merge($item1, $item2, $item3));
      
      /*
      var_dump($item_keys); // Produces the following:
      
      array(5) {
          [0]=> string(3) "red"
          [1]=> string(5) "green"
          [2]=> string(6) "yellow"
          [3]=> string(4) "blue"
          [4]=> string(6) "orange"
      }
      
      */
      
      foreach( $items as $sub )
      {
      
          foreach( $sub as $category => $points ) {
      
              foreach( $item_keys as $key ) {
      
                  // Sort the points within that category
                  if ( $key == $category ) {
      
                      $final[$category][] = $points;
      
                      // Grab the highest or most popular category/point?
                      $check[$category] = max($final[$category]);
      
                  }
      
              }
      
          }
      
      }
      
      // sort by popularity
      arsort($check, SORT_NUMERIC);
      
      /*
      var_dump($check); // Produces the following:
      
      array(5) {
          ["red"]=> int(6)
          ["blue"]=> int(5)
          ["green"]=> int(4)
          ["yellow"]=> int(2)
          ["orange"]=> int(1)
      }
      
      */
      
      // total points = 18
      var_dump(array_sum($check));