Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/303.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 计算项目出现的集合数的更快方法?_C#_Algorithm_Optimization_Hashset - Fatal编程技术网

C# 计算项目出现的集合数的更快方法?

C# 计算项目出现的集合数的更快方法?,c#,algorithm,optimization,hashset,C#,Algorithm,Optimization,Hashset,我有一个书签列表。每个书签都有一个关键字列表(存储为哈希集)。我也有一套所有可能的关键词(“宇宙”) 我想找到出现在大多数书签中的关键字 我有1356个书签,总共有698539个关键词,其中187358个是唯一的 如果我遍历宇宙中的每个关键字,并计算它出现在其中的书签的数量,我将进行254057448次检查。这在我的机器上需要35秒 算法非常简单: var biggest = universe.MaxBy(kw => bookmarks.Count(bm => bm.Keywords

我有一个书签列表。每个书签都有一个关键字列表(存储为哈希集)。我也有一套所有可能的关键词(“宇宙”)

我想找到出现在大多数书签中的关键字

我有1356个书签,总共有698539个关键词,其中187358个是唯一的

如果我遍历宇宙中的每个关键字,并计算它出现在其中的书签的数量,我将进行254057448次检查。这在我的机器上需要35秒

算法非常简单:

var biggest = universe.MaxBy(kw => bookmarks.Count(bm => bm.Keywords.Contains(kw)));
使用

我不确定是否有可能加快速度,但我能做些什么吗?也许可以将其并行化


dtb的解决方案需要不到200毫秒的时间来构建宇宙并找到最大的元素。这么简单

var freq = new FreqDict();
foreach(var bm in bookmarks) {
    freq.Add(bm.Keywords);
}
var biggest2 = freq.MaxBy(kvp => kvp.Value);

FreqDict
只是我在
字典

上创建的一个小类,您可以获取所有关键字,对它们进行分组,并获得最大的组。这会占用更多内存,但速度应该更快

我试过这个,在我的测试中,速度快了80倍:

string biggest =
  bookmarks
  .SelectMany(m => m.Keywords)
  .GroupBy(k => k)
  .OrderByDescending(g => g.Count())
  .First()
  .Key;
试运行:

1536 bookmarks
153600 keywords
74245 unique keywords

Original:
12098 ms.
biggest = "18541"

New:
148 ms.
biggest = "18541"

你不需要遍历整个宇宙。这个想法是创建一个查找和跟踪max

    public Keyword GetMaxKeyword(IEnumerable<Bookmark> bookmarks)
    {
        int max = 0;
        Keyword maxkw = null;

        Dictionary<Keyword, int> lookup = new Dictionary<Keyword, int>();

        foreach (var item in bookmarks)
        {
            foreach (var kw in item.Keywords)
            {
                int val = 1;

                if (lookup.ContainsKey(kw))
                {
                    val = ++lookup[kw];
                }
                else
                {
                    lookup.Add(kw, 1);
                }

                if (max < val)
                {
                    max = val;
                    maxkw = kw;
                }
            }
        }

        return maxkw;
    }
public关键字GetMaxKeyword(IEnumerable书签)
{
int max=0;
关键词maxkw=null;
字典查找=新建字典();
foreach(书签中的变量项)
{
foreach(项目中的var kw.关键字)
{
int-val=1;
if(查找容量(kw))
{
val=++查找[kw];
}
其他的
{
查找。添加(千瓦,1);
}
如果(最大值
我没有你的样本数据,也没有做过任何基准测试,但我会尝试一下。可以改进的一个问题是,大多数
bm.Keywords.Contains(kw)
检查都是未命中的,我认为这些是可以避免的。最受限制的是任何一个给定书签的关键字集(即:它通常比宇宙小得多),因此我们应该从这个方向开始,而不是从另一个方向开始

我在想这些事情。内存要求要高得多,因为我没有做任何基准测试,它可能会慢一些,或者没有帮助,但是如果我的答案不适合你,我会删除它

Dictionary<string, int> keywordCounts = new Dictionary<string, int>(universe.Length);
foreach (var keyword in universe)
{
    keywordCounts.Add(keyword, 0);
}

foreach (var bookmark in bookmarks)
{
    foreach (var keyword in bookmark.Keywords)
    {
        keywordCounts[keyword] += 1;
    }
}

var mostCommonKeyword = keywordCounts.MaxBy(x => x.Value).Key;
Dictionary关键字计数=新字典(universe.Length);
foreach(宇宙中的var关键字)
{
关键字计数。添加(关键字,0);
}
foreach(书签中的var书签)
{
foreach(bookmark.Keywords中的var关键字)
{
关键词计数[关键词]+=1;
}
}
var mostCommonKeyword=keywordCounts.MaxBy(x=>x.Value).Key;
50毫秒python格式:

>>> import random

>>> universe = set()
>>> bookmarks = []
>>> for i in range(1356):
...     bookmark = []
...     for j in range(698539//1356):
...         key_word = random.randint(1000, 1000000000)
...         universe.add(key_word)
...         bookmark.append(key_word)
...     bookmarks.append(bookmark)
...
>>> key_word_count = {}
>>> for bookmark in bookmarks:
...     for key_word in bookmark:
...         key_word_count[key_word] = key_word_count.get(key_word, 0) + 1
...

>>> print max(key_word_count, key=key_word_count.__getitem__)
408530590

>>> print key_word_count[408530590]
3
>>>

当你等待这35秒过去的时候,它给你的CPU带来了多大的压力?@IneedHelp:观察任务管理器(Win7)中的性能选项卡,CPU使用率从1%跳到25%左右,然后稳定在12%左右。我有4个核心,从超读到8。@马克:你有没有考虑过在创建宇宙时计算每个关键字出现的次数?@dtb:没有……我没有想到。创造宇宙只需要100毫秒;它只是做了一系列的
联合
。如果我用一本
字典
来做一些计数,我想不会慢很多,它会给我更多的信息。好奇。不管怎样,我想用一个“缩小的宇宙”递归地应用它——也就是说,我正在对集合覆盖问题实现一个贪婪的解决方案。我想我仍然可以应用这个解决方案,不过我不会在第二次添加任何新条目。我明天早上试试。谢谢@除了计数之外,为了实现并行化,您可以尝试从中对
universe.aspallel()…
进行基准测试。请注意,它不需要更快…这是非常光滑的。分组后尝试
.MaxBy(g=>g.Count())
,而不是使用排序。@erisco:谢谢。使用
MaxBy
应该比排序快,但我看不出测试中有什么不同。我猜这部分操作只是整个操作中的一小部分,因此没有实际意义。对于测试时间,您可能应该多次运行它们,例如1000次,因为初始化将花费太多时间。另外,我很确定您使用for循环的方法比linq运行得更快。@SaeedAmiri:将项目循环到字典中与GroupBy基本相同。使用Linq时总会有一些开销,因此您可以通过自己重写来提高速度,但另一方面,您可以通过使用框架中的方法来降低出现错误的风险。是的,我们可以避免开销,提高性能,增加风险,降低代码可读性和维护,但这一切都取决于项目,如果OP高度关注性能,我建议这样做。我在用字典,但我不想同时存储最大值。让我看看这能节省多少时间…不。不会节省任何时间。甚至可能需要花费几毫秒。我认为每个add上的额外操作比在最后进行一次迭代来找到最大值更重要。我很好奇为什么在Python中这样更快。我现在也在做同样的事情。可能是因为我的键是字符串?TBH的50毫秒一点也不准确。这取决于计算机的速度,是的,整数可能更快?不确定。接受这个,因为它似乎是最快的解决方案,尽管它们都很相似。