简体   繁体   中英

Filter and Sort a multidimensional array in PHP

I'm building an image gallery and want to throw some promo banners in at random points to promote certain offers to users. Given the following array comes from a database query:

    Array
    (
        [0] => Array
            (
                [insertDate] => 2014-11-10 11:22:58
                [keyword] => standard
                [mediaClass] => image
                [mediaURL] => http://image1.jpg
                [promoURL] => 
            )

        [1] => Array
            (
                [insertDate] => 2014-11-10 11:23:08
                [keyword] => promo
                [mediaClass] => image
                [mediaURL] => http://image2.jpg
                [promoURL] => http://www.google.com
            )

        [2] => Array
            (
                [insertDate] => 2014-11-10 11:23:18
                [keyword] => standard
                [mediaClass] => image
                [mediaURL] => http://image3.jpg
                [promoURL] => 
            )

        [3] => Array
            (
                [insertDate] => 2014-11-10 11:23:28
                [keyword] => standard
                [mediaClass] => image
                [mediaURL] => http://image4.jpg
                [promoURL] => 
            )

        [4] => Array
            (
                [insertDate] => 2014-07-08 11:23:38
                [keyword] => promo
                [mediaClass] => image
                [mediaURL] => http://image5.jpg
                [promoURL] => http://www.google.com
            )

        [5] => Array
            (
                [insertDate] => 2014-07-08 11:23:48
                [keyword] => standard
                [mediaClass] => image
                [mediaURL] => http://image6.jpg
                [promoURL] => 
            )
     )

I am trying to do two things;

1)

Ensure there is only one promo image per 5 standard images (in this example there are 2 so one would need to be removed/filtered from the array using the keyword key). This is to avoid spamming the user with too many promotional banners.

2)

Ramdomise the position of any images with the promo keyword but still maintain the order of images with the standard keyword by insertDate.

Bearing in mind the size of these result sets will always differ, what would be the best way to programmatically achieve this?

edit: I created the following function to tackle the first part:

function limitMediaPromos($array, $key, $value, $limit)
{
    // count the number of promo images
    if($count = $this->countElementsWithValue($array, $key, $value))
    {
        // find the avg number of promos per media set
        $avg = floor((count($array) / $count));

        // remove promo element if avg is over set limit
        if($avg > $limit)
        {
            $array = $this->removeElementWithValue($array, $key, $value);
        }
    }

    return $array;
}

For better performance sort on the database side, and remove the mediaSort function and the usort($medias, 'mediaSort'); below.

function isMedia($var)  {
    return empty($var['promoURL']);
}

function isPromo($var)
{
    return !empty($var['promoURL']);
}

function mediaSort($mediaOne, $mediaTwo)
{
    return (strtotime($mediaOne['insertDate']) <= strtotime($mediaTwo['insertDate']));
}

function getImages($input)
{
    // Get the promos. O(n).
    $promos = array_filter($input, "isPromo");
    // randomize them. O(n).
    shuffle($promos);

    // Get the medias. O(n)
    $medias = array_filter($input, "isMedia");
    // Sort them (ideally sort it on the database side and skip this step). O(n log n)
    usort($medias, 'mediaSort');

    $promoOdds = 1/5;
    $promoGap = 5;
    $returnIndex = 0;

    $return = array();
    foreach ($medias as $media) {
        if (is_null($lastPromoIndex)
            || $returnIndex > $lastPromoIndex + $promoGap
        ) {
            if (rand(1,1/$promoOdds) == 1) {
                $return[] = array_pop($promos);
                $lastPromoIndex = $returnIndex;
            }
        }
        $return[] = $media;
        $returnIndex++;
    }

    if (is_null($lastPromoIndex)
        || $returnIndex > $lastPromoIndex + $promoGap
    ) {
        $return[] = array_pop($promos);
    }

    return $return;
}

print_r(getImages($input));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM