[英]c# comparing list of IDs
我有一个List<Keyword>
,其中关键字类是:
public string keyword;
public List<int> ids;
public int hidden;
public int live;
public bool worked;
关键字有自己的关键字,一组20个ID,默认情况下,实时设置为1,隐藏为0。
我只需要遍历整个主列表,以使那些具有相同id的id大于6的关键字无效,因此比较每对,如果第二对相对于第一个具有重复的id超过6个,则hidden设置为1并活到0。
该算法非常基础,但是当主列表包含许多元素时,它会花费很长时间。
我试图猜测是否可以使用任何方法来提高速度。
我使用的基本算法是:
foreach (Keyword main_keyword in lista_de_keywords_live)
{
if (main_keyword.worked) {
continue;
}
foreach (Keyword keyword_to_compare in lista_de_keywords_live)
{
if (keyword_to_compare.worked || keyword_to_compare.id == main_keyword.id) continue;
n_ids_same = 0;
foreach (int id in main_keyword.ids)
{
if (keyword_to_compare._lista_models.IndexOf(id) >= 0)
{
if (++n_ids_same >= 6) break;
}
}
if (n_ids_same >= 6)
{
keyword_to_compare.hidden = 1;
keyword_to_compare.live = 0;
keyword_to_compare.worked = true;
}
}
}
下面的代码是如何使用HashSet
解决问题的示例。 但是,我不建议在这种情况下使用它。 另一方面,对ID进行排序以使比较仍然更快的想法。 在控制台项目中运行它以进行尝试。
请注意,完成向关键字添加新ID后,便对其进行排序。 这样可以使以后的比较更快。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
namespace KeywordExample
{
public class Keyword
{
public List<int> ids;
public int hidden;
public int live;
public bool worked;
public Keyword()
{
ids = new List<int>();
hidden = 0;
live = 1;
worked = false;
}
public override string ToString()
{
StringBuilder s = new StringBuilder();
if (ids.Count > 0)
{
s.Append(ids[0]);
for (int i = 1; i < ids.Count; i++)
{
s.Append(',' + ids[i].ToString());
}
}
return s.ToString();
}
}
public class KeywordComparer : EqualityComparer<Keyword>
{
public override bool Equals(Keyword k1, Keyword k2)
{
int equals = 0;
int i = 0;
int j = 0;
//based on sorted ids
while (i < k1.ids.Count && j < k2.ids.Count)
{
if (k1.ids[i] < k2.ids[j])
{
i++;
}
else if (k1.ids[i] > k2.ids[j])
{
j++;
}
else
{
equals++;
i++;
j++;
}
}
return equals >= 6;
}
public override int GetHashCode(Keyword keyword)
{
return 0;//notice that using the same hash for all keywords gives you an O(n^2) time complexity though.
}
}
class Program
{
static void Main(string[] args)
{
List<Keyword> listOfKeywordsLive = new List<Keyword>();
//add some values
Random random = new Random();
int n = 10;
int sizeOfMaxId = 20;
for (int i = 0; i < n; i++)
{
var newKeyword = new Keyword();
for (int j = 0; j < 20; j++)
{
newKeyword.ids.Add(random.Next(sizeOfMaxId) + 1);
}
newKeyword.ids.Sort(); //sorting the ids
listOfKeywordsLive.Add(newKeyword);
}
//solution here
HashSet<Keyword> set = new HashSet<Keyword>(new KeywordComparer());
set.Add(listOfKeywordsLive[0]);
for (int i = 1; i < listOfKeywordsLive.Count; i++)
{
Keyword keywordToCompare = listOfKeywordsLive[i];
if (!set.Add(keywordToCompare))
{
keywordToCompare.hidden = 1;
keywordToCompare.live = 0;
keywordToCompare.worked = true;
}
}
//print all keywords to check
Console.WriteLine(set.Count + "/" + n + " inserted");
foreach (var keyword in set)
{
Console.WriteLine(keyword);
}
}
}
}
效率低下的明显原因是您计算两个列表(id)的交集的方式。 该算法为O(n ^ 2)。 这是关系数据库为每个联接解决的问题,您的方法将称为循环联接。 主要的有效策略是哈希联接和合并联接。 对于您的情况,我猜后一种方法可能更好,但是如果您愿意,也可以尝试HashSets。
效率低下的第二个原因是重复一切两次。 由于(a联接b)等于(b联接a),因此整个List<Keyword>
不需要两个循环。 实际上,您只需要遍历非重复项即可。
使用此处的一些代码,您可以编写如下算法:
Parallel.ForEach(list, k => k.ids.Sort());
List<Keyword> result = new List<Keyword>();
foreach (var k in list)
{
if (result.Any(r => r.ids.IntersectSorted(k.ids, Comparer<int>.Default)
.Skip(5)
.Any()))
{
k.hidden = 1;
k.live = 0;
k.worked = true;
}
else
{
result.Add(k);
}
}
如果仅用索引操作方法替换linq(请参阅上面的链接),我想它会快一点。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.