LINQ查询以查找具有最多重复项的多维数组的字符串

时间:2016-03-08 11:43:26

标签: c# linq

我编写了一个函数,它给出了一个具有多个正则表达式字符串的Match的多维数组。 (FileCheck [] [])

  1. FileCheck [0] //此字符串[]包含所有文件名
  2. FileCheck [1] //此字符串[]为0或1,具体取决于找到的正则表达式匹配。
  3. FileCheck [2] //此字符串[]包含第一个找到的正则表达式的索引。

        foreach (string File in InputFolder)
        {
            int j = 0;
            FileCheck[0][k] = Path.GetFileName(File);
            Console.WriteLine(FileCheck[0][k]);
            foreach (Regex Filemask in Filemasks)
            {
                if (string.IsNullOrEmpty(FileCheck[1][k]) || FileCheck[1][k] == "0")
                {
                    if (Filemask.IsMatch(FileCheck[0][k]))
                    {
                        FileCheck[1][k] = "1";
                        FileCheck[2][k] = j.ToString(); // This is the Index of the Regex thats Valid
                    }
                    else
                    {
                        FileCheck[1][k] = "0";
                    }
                    j++;
                }
                Console.WriteLine(FileCheck[1][k]);
            }
            k++;
        }
        Console.ReadLine();
    
        // I need the Index of the Regex with the most valid hits
    
  4. 我正在尝试编写一个函数,它为我提供了重复次数最多的RegexIndex字符串。 这是我尝试但没有工作:((我只得到最重复的字符串计数,但不是字符串本身)

            // I need the Index of the Regex with the most valid hits
            var LINQ = Enumerable.Range(0, FileCheck[0].GetLength(0))
                .Where(x => FileCheck[1][x] == "1")
                .GroupBy(x => FileCheck[2][x])
                .OrderByDescending(x => x.Count())
                .First().ToList();
            Console.WriteLine(LINQ[1]);
    

    示例数据

            string[][] FileCheck = new string[3][];
            FileCheck[0] = new string[]{ "1.csv", "TestValid1.txt", "TestValid2.txt", "2.xml", "TestAlsoValid.xml", "TestValid3.txt"};
            FileCheck[1] = new string[]{ "0","1","1","0","1","1"};
            FileCheck[2] = new string[]{ null, "3", "3", null,"1","2"};
    

    在这个例子中,我需要Linq查询的结果:

     string result = "3";
    

4 个答案:

答案 0 :(得分:1)

您的问题和代码似乎非常复杂。我猜你有一个文件名列表和另一个文件掩码列表(正则表达式),你想找到匹配大多数文件名的文件掩码。这是一种方法:

var fileNames = new[] { "1.csv", "TestValid1.txt", "TestValid2.txt", "2.xml", "TestAlsoValid.xml", "TestValid3.txt" };
var fileMasks = new[] { @"\.txt$", @"\.xml$", "valid" };
var fileMaskWithMostMatches = fileMasks
  .Select(
    fileMask => new {
      FileMask = fileMask,
      FileNamesMatched = fileNames.Count(
        fileName => Regex.Match(
            fileName,
            fileMask,
            RegexOptions.IgnoreCase | RegexOptions.CultureInvariant
          )
          .Success
      )
    }
  )
  .OrderByDescending(x => x.FileNamesMatched)
  .First()
  .FileMask;

使用示例数据,fileMaskWithMostMatches的值为valid

请注意,Regex类将对正则表达式进行一些缓存,但如果您有许多正则表达式,则在隐含fileNames.Count for-each循环之外创建正则表达式会更有效一次又一次地重新创建相同的正则表达式(根据复杂性,创建正则表达式可能需要花费非常少的时间)。

答案 1 :(得分:1)

作为Martin答案的替代方案,这里是您现有Linq查询的一个更简单的版本,可以提供所需的结果;

var LINQ = FileCheck[2]
              .ToLookup(x => x)                   // Makes a lookup table
              .OrderByDescending(x => x.Count())  // Sorts by count, descending
              .Select(x => x.Key)                 // Extract the key
              .FirstOrDefault(x => x != null);    // Return the first non null key
                                                  // or null if none found.

答案 2 :(得分:1)

使用当前代码,用'Key'代替'ToList()'可以解决问题。

var LINQ = Enumerable.Range(0, FileCheck[0].GetLength(0))
            .Where(x => FileCheck[1][x] == "1")
            .GroupBy(x => FileCheck[2][x])
            .OrderByDescending(x => x.Count())
            .First().Key;

由于索引对于未找到的值为空,您还可以过滤掉空值并跳过查看FileCheck [1]数组。例如:

var maxOccurringIndex = FileCheck[2].Where(ind => ind != null)
        .GroupBy(ind=>ind)
        .OrderByDescending(x => x.Count())
        .First().Key;

但是,只是一个建议,你可以使用类而不是嵌套数组,例如:

class FileCheckInfo
{
    public string File{get;set;}
    public bool Match => Index.HasValue;
    public int? Index{get;set;}

    public override string ToString() => $"{File} [{(Match ? Index.ToString() : "no match")}]";
}

假设InputFolder是一个可枚举的字符串,而Filemasks是一个可枚举的'Regex',则可以用以下内容填充数组:

FileCheckInfo[] FileCheck = InputFolder.Select(f=>
    new FileCheckInfo{
        File = f, 
        Index = Filemasks.Select((rx,ind) => new {ind, IsMatch = rx.IsMatch(f)}).FirstOrDefault(r=>r.IsMatch)?.ind
        }).ToArray();

获得最大值将大致相同:

var maxOccurringIndex = FileCheck.Where(f=>f.Match).GroupBy(f=>f.Index).OrderByDescending(gr=>gr.Count()).First().Key;

编辑 PS,以上都假设您需要重复使用结果,如果您只需要找到最大值,您可以使用Martin建议的方法更好! 如果目标仅是获得最大值,则可以使用:

var maxOccurringIndex = Filemasks.Select((rx,ind) => new {ind, Count = InputFolder.Count(f=>rx.IsMatch(f))})
        .OrderByDescending(m=>m.Count).FirstOrDefault()?.ind;

答案 3 :(得分:0)

这不是更容易吗?

string result = FileCheck[2]
    .Where(x => x != null)
    .GroupBy(x => x)
    .OrderByDescending(x => x.Count())
    .FirstOrDefault().Key;