【问题标题】:Count number of times a token appears in a document [closed]计算令牌在文档中出现的次数[关闭]
【发布时间】:2013-08-29 15:46:41
【问题描述】:

我已经从文档中提取了标记并将它们插入到一个数组中。现在我想要确定一个令牌在文档中出现的次数。

我脑海中的当前算法获取每个令牌并扫描整个令牌数组以找到相似的令牌。正如您所猜测的那样,它的可扩展性并不高。

我一直在寻找其他一些好的算法来帮助我解决这个问题。

我对 SO 有一些类似的问题,但他们都假设令牌是在编译时提供的。

【问题讨论】:

  • 如果你已经在数组中拥有了令牌,你就不能只做array.Length...吗?
  • 请提供您当前的代码、您的数据是什么样的以及您的期望。
  • 数组有所有的标记,他本质上是想计算数组中的重复项
  • 某种哈希表数据结构在这里是最好的。然后你可以在 O(N) 中完成这个
  • 我还是很困惑他是想用Java还是C#,因为java没有lambda

标签: c# .net nlp token


【解决方案1】:

为了简化示例,假设“令牌”是整数。使用group by 将标记划分为等价类,然后计算每个组的大小。

var tokens = new[] { 10, 20, 30, 10, 30, 20, 20, 20, 10 };
var grouped = from token in tokens group token by token;
foreach (var grp in grouped)
     Console.WriteLine("{0} {1}", grp.Key, grp.Count());

输出是:

10 3
20 4
30 2

【讨论】:

  • +1 超级简单的解释
  • @WinCoder:我怎么知道?试试看。只有您知道您的性能要求是什么。
  • 从令牌中的令牌按令牌分组;这听起来太搞笑了
  • @Cruncher:你更喜欢这个等价物吗? var grouped = tokens.GroupBy(token => token)
  • @WinCoder:您实际上是执行查询,还是只是构建它?构建查询是即时的。实际执行它们——例如通过foreach 运行——可能非常耗时。
【解决方案2】:

使用 ID 为 String(即令牌)和 Integer(即计数)的 Map/Hashmap。

这是您需要的逻辑。

对于每个令牌:

如果令牌存在,则通过令牌 id 获取对象来增加计数并替换旧令牌
如果 token 不存在,则将 token 添加到 map 并将整数值设置为 1。

【讨论】:

  • 在 C# 中,这通常是 Dictionary
  • @Brian 同意!但原来是java/c#
  • 是的,java 是第一个标签
【解决方案3】:

不确定是否完全理解问题,但这就是您可以对值(令牌)进行分组,然后计算它们出现的次数的方法。

List<string> tokens = new List<string> { "A", "B", "A", "A", "B", "C"};
var tokensCount = tokens.GroupBy(g => g).Select(g => new KeyValuePair<string, int>(g.Key, g.Count()));
// Returns A 3, B 2, C 1

【讨论】:

  • 如果你没有完全理解这个问题,那么先发表评论难道没有意义吗?
  • @Cruncher 发表了评论,他回复说他无法发布代码、实际数据或预期结果。所以这是我能得到的最接近的。
【解决方案4】:

此答案适用于 Java

您可以使用HashMap&lt;String,Integer&gt;(或SortedMap&lt;String,Integer&gt;,如果您希望按字母顺序排列结果),其中keys 是标记,value 是计数。对于列表中的每个元素,您需要检查它是否已经存在于地图中。如果不是,则创建一个值为1 的新键。如果它已经存在,您只需将 value(计数)增加 1。

HashMap<String,Integer> counts= new HashMap<String,Integer>() ;
for(String e: myTokenList ) {
    if( counts.get(e) == null )
        counts.put(e,1);
    else
        counts.put(e,counts.get(e)+1);
}

有一个可能的微优化:

HashMap<String,Integer> counts= new HashMap<String,Integer>() ;
for(String e: myTokenList ) {
    Integer c= counts.get(e) ;
    if( c == null )
        counts.put(e,1);
    else
        counts.put(e,c+1);
}

【讨论】:

    【解决方案5】:

    好的,根据其他一些建议,不要将文档中的单词插入数组中(除非您有充分的理由,但您的问题中尚未突出显示)。

    相反,将其插入地图/字典中,例如在下面的示例中(注意可以更有效地完成,但这显示了明确执行的每个步骤)。

    var wordCounts = new Dictionary<string, int>();
    var wordSeparators = new char[] {',', ' ', '\t', ';' /* etc */ };
    using (var reader = File.OpenText("allmaywords.txt")
    {
        while (!reader.EndOfStream)
        {
            var words = reader
                .ReadLine() 
                .Split(wordSeparators, StringSplitOptions.RemoveEmptyEntries)
                .Select(f => f.Trim()).ToList();
            foreach (var word in words)
            {
                if (!wordCounts.ContainsKey(word))
                    wordCounts[word] = 1;
                else
                    wordCounts[word] = wordCounts[word] + 1;
            } 
        }    
    }
    

    现在您还可以通过以下方式访问所有唯一词(或标记):

    var uniqueTokens = wordCounts.Keys;
    

    你可以查明是否存在令牌:

    var gotAFoo = wordCounts.ContainsKey("Foo");
    

    以及它出现的频率:

    var numbeOfFoosGiven = wordCounts["Foo"];
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-02
      • 2021-07-06
      • 1970-01-01
      相关资源
      最近更新 更多