【问题标题】:PHP: Aggregating a list of documentsPHP:聚合文档列表
【发布时间】:2013-07-04 06:28:49
【问题描述】:

我有 3 个数组,每个数组都包含一个动态生成的文档列表。 (列表会根据用户搜索的内容而变化)

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

数组是多维的,包含描述等其他信息。

所以如果我想输出第六个文档的名称和描述,我会写:

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

一个特定的文档可能包含在所有三个列表中,也可能一个列表都不包含。我要做的是使用以下公式按文档总分对文档进行排名:

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

我正在想办法做到这一点,但我一无所获。

如果“document a”在list1中排名第1,在list2中排名第2,在list3中排名第4 ,如何应用以下公式并将分数相加。

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

我知道我需要根据$list1['documentname'] is equal to $list2['documentname']等应用代码,但我不知道如何实现。

编辑:

以下代码是我尝试过的。如果 documentname[$i] 值相同,它会为 list1 中的文档提供正确的分数,并为 list2 中的文档评分。

不过这个方法看起来很啰嗦,只能解决一半的问题。似乎我必须在循环内有许多循环来解决这个问题,这不是很有效

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;

    }

另一个问题是 for 循环中的条件 $i&lt;count($list1) 假设 $list1 是最长的数组,如果 $list3 更长怎么办?我只是说$i&lt;count($list1) &amp;&amp; $i&lt;count($list2) &amp;&amp; $i&lt;count($list2)吗?

欢迎任何建议,我将不胜感激。

谢谢各位。

【问题讨论】:

    标签: php arrays aggregation ranking scoring


    【解决方案1】:

    我们有三个映射,它们按对象在内部的排名方式排序,每个对象在哪里是全局唯一的,由它们的“名称”键控。例如,在第一个列表中,MewMew 排名第 1,Spot 排名第 2,Johnny 排名第 3。请注意,MewMew 不在 List 3 中,Ruby 不在 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.")
    );
    

    我建议的方法是创建一个数据结构,该结构将保存所有三个列表的组合,由它们的全局键“名称”作为键,并为每个条目维护一个运行总分。幸运的是,您选择用于计算聚合 (SUM ( 1 / (60 + i)) 的算法非常适合运行计算方法。另请注意,这样做可以让您实际扩展为任意数量的输入列表,而不仅仅是此处给出的三个。

    $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);
    

    $combinedRank 变量包含按名称计算的聚合排名。鉴于当前公式,预期值为:

    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
    

    您可以根据需要编写额外的代码来对结果进行排序并提取描述信息。

    【讨论】:

    • 这似乎是一个有用的功能。问题是文档列表是动态生成的,每次用户搜索时它都会改变。所以我无法搜索特定的文档。我应该在我的问题中说明这一点;已编辑。
    • 我不完全确定为什么动态生成的数组会改变这个问题。 PHP 是单线程的,所以一旦你经历了搜索过程,数据就不会在你下面改变。您能否提供更多有关列表数组中数据布局的详细信息和示例?什么是键,什么是值?
    • 嘿@Anthop 数组是这样的:$list1 = array('documentname','description') 所以如果我想输出第六个文档的名称和描述,我会写:echo $list1[5]['documentname'].$newline.$list1[5]['description'];
    • 查看我的更新答案。由于您正在尝试聚合来自多个来源的数据,我建议您在构建聚合时添加一个单独的数据结构来存储您的工作。
    • 谢谢@Anthop,我已经测试了你的代码,它似乎可以正确计算分数。现在我将尝试对结果进行排序并提取其他信息。
    猜你喜欢
    • 1970-01-01
    • 2020-07-26
    • 2017-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多