【问题标题】:Objective-C: How to find the most common string in an array?Objective-C:如何在数组中找到最常见的字符串?
【发布时间】:2025-11-23 19:20:07
【问题描述】:

我有一个来自在线数据库的字符串数组,我试图确定最常用的单词。数组中的值会有所不同,但我想检查我正在使用的任何集合或单词中最常见的单词。如果理论上我有以下数组...

NSArray *stringArray = [NSArray arrayWithObjects:@"Duck", @"Duck", @"Duck", @"Duck", @"Goose"];

我如何遍历这个数组来确定最常见的字符串,这显然是“Duck”?

【问题讨论】:

  • 我会将其转换为 NSDictionary (*.com/questions/1414852/…),如果单词 (key) 已经存在,则将值 (count) 加一,然后循环查找最大值。
  • 最好的方法可能是以一种可以告诉您的方式编写查询......这可能会更有效。
  • 曾经记录了一个 @mode 收集路径运算符,但有两个问题是,a) 它不再记录,b) 我无法让它工作当它被记录下来。

标签: objective-c nsstring nsarray


【解决方案1】:

您可以将单词用作字典的键。

NSMutableDictionary *words = [NSMutableDictionary dictionary];
for (NSString *word in stringArray) {
    if (!words[word]) {
        [words setValue:[NSDecimalNumber zero] forKey:word];
    }

    words[word] = [words[word] decimalNumberByAdding:[NSDecimalNumber one]];
}

现在遍历words 并找到具有最高值的键。

NSString *mostCommon;
NSDecimalNumber *curMax = [NSDecimalNumber zero];
for (NSString *key in [words allKeys]) {
    if ([words[key] compare:curMax] == NSOrderedDescending) {
        mostCommon = key;
        curMax = word[key];
    }
}

NSLog(@"Most Common Word: %@", mostCommon);

编辑:我认为我们可以做得更好,并在一个循环中完成所有操作,而不是遍历数组一次然后单独循环遍历排序字典。

NSString *mostCommon;
NSDecimalNumber *curMax = [NSDecimalNumber zero];
NSMutableDictionary *words = [NSMutableDictionary dictionary];
for (NSString *word in stringArray) {
    if (!words[word]) {
        [words setValue:[NSDecimalNumber zero] forKey:word];
    }

    words[word] = [words[word] decimalNumberByAdding:[NSDecimalNumber one]];

    if ([words[word] compare:curMax] == NSOrderedDescending) {
        mostCommon = word;
        curMax = words[word];
    }
}

NSLog(@"Most Common Word: %@", mostCommon);

这应该比我的答案预编辑快得多,尽管我不知道它与使用 NSCountedSet 答案相比如何。

【讨论】:

  • 最后一行应该是:words[word] = [words[word] decimalNumberByAdding:[NSDecimalNumber one]];否则计数不会增加。这是一个超级常见的面试问题。
  • 你是对的。我总是忘记这会返回值,而不是修改你调用它的值。
  • 谢天谢地,Swift 降低了该错误的可能性,并且该解决方案不那么冗长!
【解决方案2】:

最简单的方法大概是NSCountedSet:

NSCountedSet* stringSet = [[NSCountedSet alloc] initWithArray:strings];
NSString* mostCommon = nil;
NSUInteger highestCount = 0;

for(NSString* string in stringSet) {
    NSUInteger count = [stringSet countForObject:string];
    if(count > highestCount) {
        highestCount = count;
        mostCommon = string;
    }
}

【讨论】:

  • 这应该是公认的答案。让我的回答看起来很糟糕。
  • 请记住,这使用了一种特定的比较。它适用于字符串相同的字符串文字。但这本质上并不实际进行单词比较,而是对象比较。任何更复杂的东西都需要更多的逻辑来进行真正的字符串分析。这包括规范化字符串、处理大小写敏感性和其他语言/脚本特定语义,甚至是单词的标记化,这可能非常复杂,具体取决于语言/脚本或混合语言和脚本以及单词和匹配项的语义定义。
  • 好点;我只是想提供一个简单的示例来回答所提出的问题。
  • 优秀。简直太棒了。
  • @uchuugaka 这并不完全正确。 NSCountedSet 根据isEqual: 的结果将对象视为重复项。如果它响应YES 对集合中已经存在的任何对象的isEqual: 调用,则认为它是重复的。现在对于NSString,这意味着大小写不同,或者意味着它不是重复的……这两个词包含不同的字符。但这是一个愚蠢的观点,因为关于如何确定两个字符串是否相等的问题的答案是“使用isEqualToString:(对于 NSString 与isEqual: 相同,并且没有人在这里争论这些特殊情况)。(1 /2)
【解决方案3】:

尝试使用 NSPredicate。

NSUInteger count=0;
NSString *mostCommonStr;
for(NSString *strValue in stringArray) {
   NSUInteger countStr=[[stringArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"self MATCHES[CD] %@, strValue]]count];
   if(countStr > count) {
       count=countStr;
       mostCommonStr=strValue;
   }
}
NSLog(@"The most commonstr is %@",mostCommonStr);

【讨论】:

  • 虽然这没有我打算的解决方案那么冗长,但它肯定也更慢。 filteredArrayUsingPredicate: 通常比使用forin 循环来做同样的事情要慢,但你在stringArray 中每个单词都这样做一次(这意味着“鸭子”4 次,“鹅”一次)。使用 1000 个单词的数组来计时您的解决方案,而我的解决方案使用相同的数组。
  • 参考filteredArrayUsingPredicate:forin 循环:*.com/a/21158730/2792531
最近更新 更多