代码之家  ›  专栏  ›  技术社区  ›  Raj More

字符串是否存在检查2万次

  •  9
  • Raj More  · 技术社区  · 16 年前

    我的C盘上有20K个音乐文件,E盘上有25K个完全相似的文件夹结构。

    我遍历第一个位置,逐个文件,检查文件是否在第二个位置存在。那部分对我有用。

    检查XML文件中是否存在字符串的最佳方法是什么(我至少要做2万次)?

    6 回复  |  直到 16 年前
        1
  •  1
  •   Jimmy Hoffa    16 年前

    按字母顺序对要匹配的字符串列表进行排序,然后构建一个索引数组,该数组告诉您作为其中一个字符串的起始字符的每个字符列表的起始位置,根据种类的广度以及匹配是否区分大小写,可以索引到第二个字符。

    用流逐字符读取文件以最小化内存占用,检查索引数组以查看该字符在字符串列表中的起始位置和结束位置,以便可以拉出该字符页(如果有以这些字符组合开头的内容)。然后继续在页面内部进行筛选,直到剩下一个匹配项,下一个字符与0匹配。

    从要匹配的字符串列表中删除该字符串,如果需要,将其放入另一个列表中。然后开始检查下一个字符的索引,并在每次遇到不匹配的字符时继续这样做。

    索引为您提供了一个更有效的聚合,以最小化对其进行迭代的项数。

    这可以为您提供两个字符的深度索引:

    Dictionary<string,int> stringIndex = new Dictionary<char,int>();
    for(int i = 0; i < sortedSearchStrings.Length; i++;)
    {
        if (!stringIndex.Keys.Contains(sortedSearchStrings[i][0])) stringIndex[sortedSearchStrings[i][0]] = i;
        if (!stringIndex.Keys.Contains(sortedSearchStrings[i][0] + sortedSearchStrings[i][1])) stringIndex[sortedSearchStrings[i][0] + sortedSearchStrings[i][1]] = i;
    }
    

    然后要在列表中找到起始索引,只需访问:

    int startOfCurrentCharPage = stringIndex[string.Format("{0}{1}", lastChar, currentChar)];
    
        2
  •  3
  •   Chris Laplante    16 年前

    如果您想用最少的内存完成:

    如果您想快速完成:

    将整个文件加载到内存中,不必解析它,只需搜索每个字符串。

    编辑

        3
  •  2
  •   Eduardo Mauro    16 年前

    建议:作为文本加载,使用正则表达式来提取所需的字符串(我假设它们用特定的标记括起来),并用它们构建一个哈希列表。您可以使用列表来检查是否存在。

        4
  •  2
  •   Dirk Vollmar    16 年前

    下面是一个使用Linq的简单解决方案。运行速度足够快,可以一次性使用:

    using System;
    using System.IO;
    using System.Linq;
    using System.Xml.Linq;
    
    class ITunesChecker
    {
        static void Main(string[] args)
        {
            // retrieve file names
            string baseFolder = @"E:\My Music\";
            string[] filesM4a = Directory.GetFiles(baseFolder, "*.m4a", SearchOption.AllDirectories);
            string[] filesMp3 = Directory.GetFiles(baseFolder, "*.mp3", SearchOption.AllDirectories);
            string[] files = new string[filesM4a.Length + filesMp3.Length];
            Array.Copy(filesM4a, 0, files, 0, filesM4a.Length);
            Array.Copy(filesMp3, 0, files, filesM4a.Length, filesMp3.Length);
    
            // convert to the format used by iTunes
            for (int i = 0; i < files.Length; i++)
            {
                Uri uri = null;
                if (Uri.TryCreate(files[i], UriKind.Absolute, out uri))
                {
                    files[i] = uri.AbsoluteUri.Replace("file:///", "file://localhost/");
                }
            }
    
            // read the files from iTunes library.xml
            XDocument library = XDocument.Load(@"E:\My Music\iTunes\iTunes Music Library.xml");
            var q = from node in library.Document.Descendants("string")
                    where node.ElementsBeforeSelf("key").Where(n => n.Parent == node.Parent).Last().Value == "Location"
                    select node.Value;
    
            // do the set operations you are interested in
            var missingInLibrary = files.Except(q, StringComparer.InvariantCultureIgnoreCase);
            var missingInFileSystem = q.Except(files, StringComparer.InvariantCultureIgnoreCase);
            var presentInBoth = files.Intersect(q, StringComparer.InvariantCultureIgnoreCase);
        }
    }
    
        5
  •  1
  •   Kogitsune    16 年前

    如果是这样,你可以利用Xml.Xml文档,从那里,Xml.XmlNode.SelectNodes文件(字符串),使用xpath导航文档。我不知道文档中存在什么类型的信息,但是您对第二阶段的措辞方式给出了这样的想法:有时C:\上的路径和E:\上的路径都存在?如果是这样的话,就简单到两个IO.File.Exists存在检查,然后IO.File.Delete文件( ).

    我的意思是,不要在XML文档中搜索N次字符串,而是在文档中搜索并删除重复项,以便只在文档中运行一次。

        6
  •  0
  •   ChrisW    16 年前

    从XML中读取每个字符串并将它们写入 HashSet<string> . 如果要查找字符串,请在哈希集中查找。读取XML的代价是O(n),对HashSet进行n次查找的代价是O(n)。不要尝试在XML中重复搜索(而是在HashSet中进行20000次搜索),因为XML没有索引/优化以进行搜索。