复杂数组排序

时间:2015-07-13 18:17:23

标签: javascript jquery arrays

假设我有以下数组:

var articles = [
     {
          id: 7989546,
          tags: [
              "98#6",
              "107#6",
              "558234#7"
          ]
     },
     //...
]

此数组的每个元素代表(部分)我们网站中的某种内容。它有一个 id ,并标有 (#6)和/或 主题 (#7)。

将向用户提供包含建议或推荐标签的cookie,如下所示:

var suggestions = [
     "46#6",
     "107#6",
     "48793#7"
]

请考虑这些标记,例如将向最终用户展示的建议,例如“也许您在阅读中感兴趣......”

suggestions数组已按标记优先顺序排序。这意味着,第一个标签与用户的关联性高于第二个标签。

现在,我要做的是以相同的方式订购我的articles数组,即标记优先级

不应该应用过滤器,因为articles数组保证包含suggestions数组中至少有一个标记的元素。

如果我的文章包含标记[ "98#6", "107#6", 558234#7" ]而另一个文章标记为[ "46#6", "36987#7" ],我希望后者成为第一个,因为标记46#6的优先级高于{{1} 1 {}在107#6数组中。

如何实现这种排序(使用两个数组)?

注意:很高兴接受jQuery解决方案。

2 个答案:

答案 0 :(得分:0)

<强> jsFiddle Demo

只需创建自己的排序功能,然后使用.indexOf检查标记是否存在。您将不得不决定自己处理的问题是最容易发生碰撞的问题。如果文章标记有优先级1标记,但另一篇文章标记有3个较低优先级标记,谁优先?这里有一些逻辑,在我建议的解决方案中,我只是通过使用建议的长度和总结优先级来总结优先级。如果您愿意,这可以适用于提供不同类型的碰撞检测,但方法基本相同。

第1步:创建比较功能

这将根据tagCount的结果对数组进行降序排序。也就是说,如果tagCount为right返回值6,为left返回值3,则首先排序6。

var compareFn = function(left,right){
    return tagCount(right.tags) - tagCount(left.tags);
};

步骤2:创建tagCount“算法”以确定优先级

这简单地优先考虑最早出现的匹配,但也会对多个后来发生的匹配给予一定的权重。它通过从匹配数组的长度中减去匹配的索引来做到这一点(建议)。因此,如果有5个建议,并且第一个建议匹配,那么最终将得到值5(长度= 5 - 索引= 0)。

var tagCount = function(tags){    
    var count = 0;
    for(var i = 0; i < tags.length; i++){
        var weight = suggestions.indexOf(tags[i]);
        if(weight > -1) 
        count += tags.length - weight;
    }
    return count;
}

Stack Snippet

var articles = [
     {
          id: 7989546,
          tags: [
              "107#6",
              "558234#7"
          ]
     },
     {
          id: 756,
          tags: [
              "98#6",
              "558234#7"
          ]
     },
     {
          id: 79876,
          tags: [
              "98#6",
              "107#6",
              "558234#7"
          ]
     },
     {
          id: 7984576,
          tags: [
              "98#6",
              "107#6",
              "46#6"
          ]
     }
];
var suggestions = [
     "46#6",
     "107#6",
     "48793#7"
];
var compareFn = function(left,right){
    return tagCount(right.tags) - tagCount(left.tags);
};
var tagCount = function(tags){    
    var count = 0;
    for(var i = 0; i < tags.length; i++){
     var weight = suggestions.indexOf(tags[i]);
     if(weight > -1) 
         count += tags.length - weight;
    }
    return count;
}
var a = articles.sort(compareFn);
console.log(a);
document.querySelector("#d").innerHTML = JSON.stringify(a);
<div id="d"></div>

答案 1 :(得分:0)

我的方法:按相关性得分之和排序

给你:

var articles = [
     {
          id: 7989546,
          tags: [
              "98#6",
              "107#6",
              "558234#7"
          ]
     },
     {
          id: 8000000,
          tags: [
              "107#6",
              "107#10",
              "558234#7",
              "5555#1"
          ]
     },
     {
          id: 8333000,
          tags: [
              "46#6",
              "107#6",
              "666234#7",
              "107#6"
          ]
     }

];


var suggestions = [
     "46#6",
     "107#6",
     "48793#7"
];

您希望按标签排序articles,而标记排名则在suggestions中定义。一个简单的方法是:

步骤1)对于每篇文章,获取suggestion中每个标记的索引。如果它不存在,请丢弃。

  

给出建议[&#34; a&#34;,&#34; b&#34;,&#34; c&#34;]

     

文章标签[&#34; a&#34;,&#34; b&#34;,&#34; zzzz&#34;,&#34; yyyy&#34;]

     

将映射到索引 [0,1] (最后两个标记被丢弃,因为它们在建议列表中不存在)

步骤2)计算相关程度。排名较高的标签(较小的索引)会产生更大的价值(参见下面的函数degreeOfRelevance())。

步骤3)总计相关度,并按此值排序。因此,包含更高排名标签的文章(基于建议)将产生更高的总分。

简单示例:

  

文章&lt; 100&gt;标签:[a,b,c]

     

文章&lt; 200&gt;标签:[b,c]

     

文章&lt; 300&gt;标签:[c,d,e,f]

     

给出建议: [a,b,c]

文章将映射到分数:

  

文章&lt; 100&gt; index:[0,1] ===&gt;总分:3 + 2 = 5

     

文章&lt; 200&gt; index:[1] ===&gt;总分:2

     

文章&lt; 300&gt; index:[2] ===&gt;总分:1

     

因此,文章&lt; 100&gt;按分数排序时,它被列为最相关的文档

以下是此方法的工作代码:

function suggest(articles, suggestions){
    function degreeOfRelavance(t){
        return suggestions.length - suggestions.indexOf(t); 
    }
    function weight(tags){
        return (tags.map(degreeOfRelavance)).reduce(function(a,b){
          return a+b
        },0);
    }
    function relatedTags(a){
        return a.tags.filter(function(t){
            return suggestions.indexOf(t)>=0
        });
    }

    articles.sort(function(a,b){
        return weight(relatedTags(a)) < weight(relatedTags(b))
    });
    return articles;
}

// See the output
console.log(suggest(articles,suggestions));