iPad上的MonoTouch:如何使文本搜索更快

本文关键字:文本 搜索 何使 上的 MonoTouch iPad | 更新日期: 2023-09-27 18:17:10

我需要在一个相对较大的列表(大约37K行,每行50到100个字符)中根据用户输入进行文本搜索。搜索在输入每个字符后完成,结果显示在UITableView中。这是我当前的代码:

if (input.Any(x => Char.IsUpper(x)))
    return _list.Where(x => x.Desc.Contains(input));
else
    return _list.Where(x => x.Desc.ToLower().Contains(input));

它在MacBook运行模拟器上表现不错,但在iPad上太慢了。

我观察到的一个有趣的事情是,随着输入的增加,它花费的时间越来越长。例如,输入"examin"。输入e需要1秒,输入x需要2秒,输入a需要5秒,输入m需要28秒,以此类推。为什么呢?

我希望有一个简单的方法来改善它。

iPad上的MonoTouch:如何使文本搜索更快

始终注意避免在时间敏感代码中分配内存

例如,我们经常生成代码,经常在没有意识到的情况下分配string,例如

x => x.Desc.ToLower().Contains(input)

将分配一个字符串从ToLower返回。根据你的描述,这将发生多次。通过使用:

可以很容易地避免这种情况
x = x.Desc.IndexOf ("s", StringComparison.OrdinalIgnoreCase) != -1

注意:只需选择符合您需要的StringComparison.*IgnoreCase即可。

LINQ也很好,但是在很多情况下它隐藏了分配——也许不是在你的情况下,但是测量是使事情更快的关键。在这种情况下,使用另一种算法(就像在另一个答案中建议的那样)可以给你更好的结果(但要记住分配;-)

更新:

Mono的Contains(string)将调用,经过几次检查,以下:

CultureInfo.CurrentCulture.CompareInfo.IndexOf (this, value, 0, length, CompareOptions.Ordinal);

,您的ToLower要求使用StringComparison.OrdinalIgnoreCase完美(即相同)匹配您现有的代码(它没有做任何文化特定的比较)。

一般来说,我发现包含操作不适合搜索,所以我建议你看看WWDC 2010页面上的Mastering Core Data Session(需要登录)视频(大约10分钟)。苹果知道"contains"在移动设备上对SQLite来说很糟糕,你可以像苹果一样在他们发布的SQLite版本上"破解"FTS。

基本上,它们通过创建一个表来进行前缀匹配:

[[ pk_id || input || normalized_input ]]

其中input和normalized_input 都显式索引。然后,它们对规范化值进行前缀匹配。例如,如果用户正在搜索"依偎",到目前为止他们已经输入了"snu",那么前缀匹配查询将看起来像:

normalized_input >= 'snu' and normalized_input < 'snt'

不确定这是否翻译给你的用例,但我认为这是值得一提的。希望这对你有帮助!

您需要使用trie。见http://en.wikipedia.org/wiki/Trie