【问题标题】:Linq keyword extraction - limit extraction scopeLinq 关键字提取 - 限制提取范围
【发布时间】:2010-11-07 12:14:14
【问题描述】:

关于this solution

有没有办法限制要考虑的关键字的数量?例如,我只想计算前 1000 个单词的文本。 Linq 中有一个“Take”方法,但它有不同的用途——所有的单词都会被计算出来,并且会返回 N 条记录。正确的选择是什么?

【问题讨论】:

  • Take() 是一个惰性函数!它不会使所有单词都被计算。例如,请参阅ideone.com/WwDwg

标签: c# .net linq keyword


【解决方案1】:

只需提早申请Take - 直接在调用Split 之后:

var results = src.Split()
                 .Take(1000)
                 .GroupBy(...) // etc

【讨论】:

  • 简单的解决方案,但在我的情况下似乎效果很好。谢谢乔恩!
【解决方案2】:

好吧,严格来说,LINQ 不一定会读取所有内容; Take 将尽快停止。问题是,在相关问题中,您查看 Count,并且很难在不消耗所有数据的情况下获得 Count。同样,string.Split 将查看所有内容

但是,如果您编写了一个惰性非缓冲拆分函数(使用 yield return)并且您想要前 1000 个唯一词,那么

var words = LazySplit(text).Distinct().Take(1000);

会工作

【讨论】:

    【解决方案3】:

    Enumerable.Take 实际上会输出结果;它不会完全缓冲它的源,然后只返回第一个 N。不过,看看你原来的解决方案,问题是你想要做Take 的输入是String.Split。不幸的是,这种方法不使用任何类型的延迟执行。它急切地创建所有“拆分”的数组,然后返回它。

    因此,从某些文本中获取流式单词序列的技术类似于:

    var words = src.StreamingSplit()  // you'll have to implement that            
                   .Take(1000);
    

    但是,我确实注意到您的其余查询是:

    ...
    .GroupBy(str => str)   // group words by the value
    .Select(g => new
                 {
                    str = g.Key,      // the value
                    count = g.Count() // the count of that value
                  });
    

    请注意,GroupBy 是一个缓冲操作 - 您可以预期,来自其来源的所有 1,000 个单词最终都将存储在组输出过程中的某个位置。

    在我看来,选项是:

    1. 如果您不介意出于拆分目的浏览所有文本,那么src.Split().Take(1000) 很好。缺点是浪费时间(在不再需要后继续拆分)和浪费空间(将所有单词存储在数组中,即使只需要前 1,000 个单词)。但是,查询的 rest 不会对超出必要的单词进行操作。
    2. 如果您由于时间/内存限制而无法执行 (1),请使用 src.StreamingSplit().Take(1000) 或等效项。在这种情况下,在找到 1,000 个单词后,不会处理任何原始文本。

    请注意,在这两种情况下,这 1000 个词他们自己最终会被 GroupBy 子句缓冲。

    【讨论】:

    • 感谢您的详细回复。
    猜你喜欢
    • 2019-08-05
    • 1970-01-01
    • 1970-01-01
    • 2020-04-26
    • 1970-01-01
    • 1970-01-01
    • 2021-10-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多