【问题标题】:Help pulling out data from a PHP array based on 5 rules根据 5 条规则帮助从 PHP 数组中提取数据
【发布时间】:2010-10-20 12:35:27
【问题描述】:

我正在处理图像文件路径数组。一个典型的数组可能存储了 5 个图像文件路径。

对于每个数组,我只想提取“最佳”照片以显示为集合的缩略图。

我发现循环和数组非常令人困惑,经过 4 小时试图弄清楚如何构建它,我不知所措。

以下是我正在使用的规则:

  1. 最好的照片在其文件路径中有“-large”。并不是所有的数组都会有这样的图像,但如果有,那总是我想要提取的照片。

  2. 第二好的照片是 260 像素宽。我可以用 getimagesize 来查找。如果我找到其中之一,我想停止寻找并使用它。

  3. 第二好的照片是 265 宽。如果我找到一个我想使用它并停止寻找。

  4. 第二好的照片是 600 像素宽。同样的交易。

  5. 然后是 220px 宽。

我需要 5 个单独的 for 循环吗? 5个嵌套for循环

这是我正在尝试的:

if $image_array{    
  loop through $image_array looking for "-large"
  if you find it, print it and break;             

  if you didn't find it, loop through $image_array looking for 260px wide.
  if you find it, print it and break;
}

等等……

但这似乎不起作用。

我想根据这些标准“搜索”我的数组以找到最佳的单个图像。如果它找不到第一种类型,那么它会寻找第二种,依此类推。这是怎么做到的?

【问题讨论】:

  • 您的解决方案不是最好/最快/最优雅的解决方案,但仍然正确。如果它不起作用,则说明您的实现中存在错误。

标签: php arrays loops


【解决方案1】:
<?php

// decide if 1 or 2 is better
function selectBestImage($image1, $image2) {
    // fix for strange array_filter behaviour
    if ($image1 === 0)
        return $image2;

    list($path1, $info1) = $image1;
    list($path2, $info2) = $image2;
    $width1 = $info1[0];
    $width2 = $info2[0];

    // ugly if-block :(
    if ($width1 == 260) {
        return $image1;
    } elseif ($width2 == 260) {
        return $image2;
    } elseif ($width1 == 265) {
        return $image1;
    }  elseif ($width2 == 265) {
        return $image2;
    } elseif ($width1 == 600) {
        return $image1;
    }  elseif ($width2 == 600) {
        return $image2;
    } elseif ($width1 == 220) {
        return $image1;
    }  elseif ($width2 == 220) {
        return $image2;
    } else {
        // nothing applied, so both are suboptimal
        // just return one of them
        return $image1;
    }
}

function getBestImage($images) {
    // step 1: is the absolutley best solution present?
    foreach ($images as $key => $image) {
        if (strpos($image, '-large') !== false) {
            // yes! take it and ignore the rest.
            return $image;
        }
    }

    // step 2: no best solution
    // prepare image widths so we don't have to get them more than once
    foreach ($images as $key => $image) {
        $images[$key] = array($image, getImageInfo($image));
    }

    // step 3: filter based on width
    $bestImage = array_reduce($images, 'selectBestImage');

    // the [0] index is because we have an array of 2-index arrays - ($path, $info)
    return $bestImage[0];
}

$images = array('image1.png', 'image-large.png', 'image-foo.png', ...);

$bestImage = getBestImage($images);

?>

这应该可以工作(我没有测试过),但它不是最理想的。

它是如何工作的?首先,我们寻找绝对最好的结果,在这种情况下,-large,因为寻找子字符串是便宜的(相比之下)。

如果我们没有找到-large 图像,我们必须分析图像宽度(更昂贵!- 所以我们预先计算它们)。

array_reduce 调用一个过滤函数,该函数接受 2 个数组值并将这两个替换为函数返回的一个(更好的一个)。重复此操作,直到数组中只剩下一个值。

这个解决方案仍然不是最理想的,因为比较(即使它们很便宜)不止一次进行。我的 big-O() 符号技巧有点生疏(哈!),但我认为它是 O(n*logn)。 soulmerges 解决方案是更好的解决方案 - O(n) :)

你仍然可以改进 soulmerges 解决方案,因为不需要第二个循环:

首先,将它打包到一个函数中,这样您就可以将 return 作为中断替换。如果第一个 strstr 匹配,则返回该值并忽略其余部分。之后,您不必为每个数组键存储分数。只需比较最高的Key 变量,如果新值更高,则存储它。

<?php

function getBestImage($images) {
    $highestScore = 0;
    $highestPath  = '';

    foreach ($images as $image) {
        if (strpos($image, '-large') !== false) {
            return $image;
        } else {
            list($width) = getImageInfo($image);

            if ($width == 260 && $highestScore < 5) {
                $highestScore = 5;
                $highestPath  = $image;

            } elseif ($width == 265 && $highestScore < 4) {
                $highestScore = 4;
                $highestPath  = $image;

            } elseif ($width == 600 && $highestScore < 3) {
                $highestScore = 3;
                $highestPath  = $image;

            } elseif ($width == 220 && $highestScore < 2) {
                $highestScore = 2;
                $highestPath  = $image;
            } elseif ($highestScore < 1) {
                // the loser case
                $highestScore = 1;
                $highestPath  = $image;
            }
        }
    }

    return $highestPath;
}

$bestImage = getBestImage($images);

?>

没有测试,应该在 O(n) 中工作。无法想象一种更快、更有效的方式 atm。

【讨论】:

  • 也可以从 5 返回,因为它不会更高。
  • 不,因为'-large'-entry 可能在数组的更下方。
  • array_reduce 的初始值为 0,因此第一次调用 selectBestImage() 时,第一个参数将为 0。除此之外,这似乎是一个不错的解决方案。
  • @soulmerge:你说得对——我不记得了。真的很奇怪的行为恕我直言......和典型的 php sigh.
【解决方案2】:

您需要 3 个循环和一个默认选择。

loop through $image_array looking for "-large"
if you find it, return it;

if you didn't find it, loop through $image_array
get image width
if prefered width (260px), return it.
if $sizes[$width] not set, add filename

loop a list of prefered sizes in order and see if it is set in $sizes
if you find it, return it;

return the first image or default image;

【讨论】:

    【解决方案3】:

    另一种方法(微不足道、不那么通用、速度较慢)。一条一条检查规则:

    function getBestFile($files) {
        foreach ($files as $arrayKey => $file) {
            if (strstr($file, '-large') !== FALSE) {
                return $file;
            }
        }
        foreach ($files as $arrayKey => $file) {
            if (is260wide($file)) {
                return $file;
            }
        }
        // ...
    }
    

    【讨论】:

      【解决方案4】:
      // predefined list of image qualities (higher number = best quality)
      // you can add more levels as you see fit
      $quality_levels = array(
          260 => 4, 
          265 => 3, 
          600 => 2,
          220 => 1
      );
      
      
      if ($image_arry) {
      
          $best_image = null;
      
          // first search for "-large" in filename 
          // because looping through array of strings is faster then getimagesize
          foreach ($image_arry as $filename) {
                if (strpos('-large', $filename) !== false) {
                      $best_image = $filename;
                      break;
                  }
          }
      
          // only do this loop if -large image doesn't exist
          if ($best_image == null) {
                  $best_quality_so_far = 0;
      
              foreach ($image_arry as $filename) {
                  $size = getimagesize($filename);
                  $width = $size[0];
      
                          // translate width into quality level
                  $quality = $quality_levels[$width];
      
                  if ($quality > $best_quality_so_far) {
                      $best_quality_so_far = $quality;
                      $best_image = $filename;
                  }
              }
          }
      
          // we should have best image now
          if ($best == null) {
              echo "no image found";
          } else {
              echo "best image is $best";
          }
      }
      

      【讨论】:

        【解决方案5】:

        我会根据应用的规则数量为文件分配分数。如果您希望某些规则取代其他规则,您可以为该规则加分。

        define('RULE_POINTS_LARGE', 10);
        define('RULE_POINTS_260_WIDE', 5);
        // ...
        
        $points = array();
        foreach ($files as $arrayKey => $file) {
            $points[$arrayKey] = 0;
            if (strstr($filename, '-large') !== FALSE) {
                $points[$arrayKey] += RULE_POINTS_LARGE;
            }
            // if ...
        }
        
        // find the highest value in the array:
        $highestKey = 0;
        $highestPoints = 0;
        foreach ($points as $arrayKey => $points) {
            if ($files[$arrayKey] > $highestPoints) {
                $highestPoints = $files[$arrayKey];
                $highestKey = $arrayKey;
            }
        }
        
        // The best picture is $files[$highestKey]
        

        另外一个说明:给你的规则多个值将确保规则可以比所有其他规则“更强大”。示例:5 条规则 -> 规则值(1、2、4、8、16)。

        • 1
        • 1 + 2
        • 1 + 2 + 4

        【讨论】:

        • 谢谢。我真的希望这不是它被否决的原因。如果人们离开 cmets 解释 为什么 他们认为答案不好,我将不胜感激。
        • 我没有反对 - 不知道为什么这个答案被反对。
        • 也不是我的。它不是最佳的,但正确的(没有检查细节)。另外,据我所知,规则的组合不是必需的。同样没有组合,整个第二个循环(以及结果数组的搜索/排序)不再是必要的。
        • 是的,$highestKey 可以在同一个循环中计算。但我会把它作为练习留给读者:)
        猜你喜欢
        • 2021-11-28
        • 1970-01-01
        • 1970-01-01
        • 2019-10-24
        • 2023-03-11
        • 2021-07-22
        • 2018-09-25
        • 1970-01-01
        • 2022-01-25
        相关资源
        最近更新 更多