根据5条规则帮助从PHP数组中提取数据

时间:2009-04-20 08:31:09

标签: php arrays loops

我正在使用图像文件路径数组。典型的数组可能有5个图像文件路径存储在其中。

对于每个阵列,我想拉出“最佳”照片,以显示为该集合的缩略图。

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

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

  1. 最好的照片在文件路径中有“-large”。并非所有阵列都会有这样的图像,但如果它们这样做,那就是我想要拍摄的照片。

  2. 下一张最佳照片的宽度为260px。我可以用getimagesize来查看。如果我找到其中一个,我想停止查找并使用它。

  3. 下一张最佳照片是265张宽。如果我找到一个我想使用它并停止寻找。

  4. 下一张最佳照片是600px宽。同样的交易。

  5. 然后220px宽。

  6. 我需要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;
    }
    

    依旧......

    但这似乎没有用。

    我希望根据这些标准“搜索”我的阵列以获得最佳单张图像。如果它找不到第一个类型,那么它会查找第二个类型。怎么做的?

5 个答案:

答案 0 :(得分:0)

<?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解决方案,因为第二个循环不是必需的:

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

<?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)中工作。无法想象更快,更有效的方式。

答案 1 :(得分:0)

// 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";
    }
}

答案 2 :(得分:0)

另一种方法(琐碎,不太通用,较慢)。只需逐个检查规则:

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

答案 3 :(得分:0)

您需要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;

答案 4 :(得分:-1)

我会根据适用的规则分配文件。如果您希望某些规则取代其他规则,您可以为该规则提供更多积分。

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条规则 - &gt;规则值(1,2,4,8,16)。

  • 1&lt; 2
  • 1 + 2&lt; 4
  • 1 + 2 + 4&lt; 8