Question

I have 3 arrays, each containing a dynamically generated list of documents. (The list changes depending on what the user searches for)

$list1['documentname']
$list2['documentname']
$list3['documentname']

The array is multidimensional and contains other information such as description.

So if I wanted to output the sixth documents name and description I would write:

echo $list1[5]['documentname'].$newline.$list1[5]['description'];

A particular document may be contained in all three lists or none of the lists. What I am trying to do is rank the documents by the documents total score using the following formula:

$document_Score = (1/(60+rank_list1)) + (1/(60+rank_list2)) + (1/(60+rank_list3))

I am trying to think of a way of doing this but I am getting nowhere.

If "document a" is ranked 1 in list1, 2 in list2, and 4 in list3, how do I apply the following formula and add the scores together.

$document_Score = (1/(60+1)) + (1/(60+2)) + (1/(60+4)) //score for "**document a**"

I know that I need to apply code based on whether $list1['documentname'] is equal to $list2['documentname'] etc but I have no idea how to implement this.

Edit:

The following code is something that I tried. It gives a correct score for documents in list1, and scores for documents in list2 if the documentname[$i] value is the same.

However this method seems very long-winded, and only solves half the problem. It seems like I would have to have numerous loops inside loops to solve this which would not be very efficient

for ($i=0;$i<count($list1);$i++)
    {
            $newline="<br />";

        $list1_rank[$i] = $i+1;
        $list2_rank[$i]= $i+1;
        $list3_rank[$i]= $i+1;
        $1ist1_score[$i]= (1/(60+$list1_rank[$i]));


            if ($list1[$i]['documentname']== $list2[$i]['documentname'])
            {
                $list_1_and_2score[$i]=$list1_score[$i]+ (1/(60+$list2_rank[$i]));
            }


            if ($list1[$i]['documentname']!= $list2[$i]['documentname'])
            {
                $list2_score[$i]=(1/(60+$list2_rank[$i]));
            }
            //Outputting the scores calculated:
            echo $newline."List 1 Document Name: ".$list1[$i]['documentname'].$newline."List 2 Document Name: ".$list2[$i]['documentname'].$newline."List 1 Score: $list1_score[$i]".$newline."List 2 Score: $list2_score[$i]".$newline."Combined Score: $list_1_and_2score[$i]".$newline;

    }

Another problem is the condition in the for loop, $i<count($list1) , assumes that $list1 is the longest array, what if $list3 is longer? Do I simply say $i<count($list1) && $i<count($list2) && $i<count($list2)?

Any suggestions at all are welcome and I would be very grateful.

Thanks guys.

Was it helpful?

Solution

We have three maps which are ordered by how objects are ranked internally and where each object is globally unique as keyed by their "name". For example, in the first list, MewMew is ranked 1st, Spot 2nd, and Johnny 3rd. Note that MewMew is not ranked in List 3, and Ruby is not ranked in List 1.

$list1 = array
(
    array("name" => "MewMew", "description" => "A golden cat."),
    array("name" => "Spot", "description" => "A playful Dalmation."),
    array("name" => "Johnny", "description" => "A big angel fish.")
);

$list2 = array
(
    array("name" => "Spot", "description" => "A playful Dalmation."),
    array("name" => "MewMew", "description" => "A golden cat."),
    array("name" => "Ruby", "description" => "A beautiful parakeet."),
    array("name" => "Johnny", "description" => "A big angel fish.")
);

$list3 = array
(
    array("name" => "Johnny", "description" => "A big angel fish."),
    array("name" => "Spot", "description" => "A playful Dalmation."),
    array("name" => "Ruby", "description" => "A beautiful parakeet.")
);

The method I would suggest is to create a data structure which will hold the combination of all three lists, keyed by their global key, the "name", and maintains a running aggregate score for each entry. Fortunately, the algorithm that you chose for calculating the aggregate (SUM ( 1 / (60 + i)) is well suited to a running calculation method. Also note that doing this this way allows you to actually expand to an arbitrary number of input lists, not just the three that are given here.

$lists = array($list1, $list2, $list3);
$combinedRank = array();

// We need to process all the input lists.
foreach ($lists as $currentList)
{
    $currentRank = 1; // The first entry is ranked "1".

    // This should perform an in-order traversal of the given list, thus highest
    // ranks will happen first, and the lowest, last:
    foreach ($currentList as $entry)
    {
        if(array_key_exists($entry["name"], $combinedRank))
        {
            // If we've already seen an entry for this name, append the value to the existing combined rank.
            $combinedRank[$entry["name"]] += 1 / (60 + $currentRank);
        }
        else
        {
            // If this the first time we've seen this name, add with initial rank of 1/(60+currentRank).
            $combinedRank[$entry["name"]] = 1 / (60 + $currentRank);
        }

        // Increment the currentRank so that later entries have lower ranks.
        $currentRank++;
    }
}

print_r($combinedRank);

The $combinedRank variable contains the calculated aggregate rank by name. Expected values are, given the current formula are:

Spot   = (1 / (60 + 2)) + (1 / (60 + 1)) + (1 / (60 + 2)) ~= 0.0487
Johnny = (1 / (60 + 3)) + (1 / (60 + 4)) + (1 / (60 + 1)) ~= 0.0479
MewMew = (1 / (60 + 1)) + (1 / (60 + 2)) + 0              ~= 0.0325
Ruby   = 0 + (1 / (60 + 3)) + (1 / (60 + 3))              ~= 0.0317

You can write additional code as necessary to sort the results and pull in description information.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top