我有一个程序,我按照文件目录的顺序解析sql脚本。团队的想法是对sql脚本的更改或添加按顺序完成,因此文件夹的命名从0到12.所以我需要按数字顺序解析这些文件夹,但是当它们按顺序解析时,这些是我将它们作为字典中的键放置的顺序:
C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\0
C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\1
C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\10
C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\11
C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\12
C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\2
C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\3
etc...
当我遍历这个字典时,我想按数字顺序运行这些文件夹,这样我就可以按照它们的设计顺序构建我的sql脚本。我将路径保存为键(字符串),我需要重新组织它们,以便按数字顺序列出路径文件夹。所以他们看起来像这样:
C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\0
C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\1
C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\2
C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\3
etc...
C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\9
C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\10
C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\11
C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\12
我的词典结构采用<string, List<string>>
的形式。我正在查看包含一系列文件夹的文件目录,每个文件夹包含一些用于构建数据库的SQL文件。我的词典键是此目录中子文件夹的文件夹路径,值是一个字符串列表,用于保存键中文件夹路径中这些文件的路径。我将编辑我的问题以提及此问题。如何按数字顺序通过我的键订购我的字典?
答案 0 :(得分:2)
根据@Paparazzi的要求
#particleground
现在您可以在 SortedDictionary , HashSet , SortedList 等中使用它,也可以
public class NaturalSortComparer : IComparer<string>
{
Regex _Regex = new Regex(@"(\d+)|(\D+)");
public int Compare(string s1, string s2)
{
var list1 = _Regex.Matches(s1).Cast<Match>().Select(m => m.Value.Trim()).ToList();
var list2 = _Regex.Matches(s2).Cast<Match>().Select(m => m.Value.Trim()).ToList();
var min = Math.Min(list1.Count, list2.Count);
int comp = 0;
for (int i = 0; i < min; i++)
{
int intx, inty;
if (int.TryParse(list1[i], out intx) && int.TryParse(list2[i], out inty))
comp = intx - inty;
else
comp = String.Compare(list1[i], list2[i]);
if (comp != 0) return comp;
}
return list1.Count - list2.Count;
}
}
PS:因为它在每次需要比较时都使用正则表达式,所以它不会非常高效...如果需要,可以生成缓存的版本用于排序更大的列表..
答案 1 :(得分:1)
所以我从一些评论中学到了很多东西,它帮助我指导了这个答案。我需要的答案取决于以下几点:
无法订购字典。要按所需顺序存储键值对,需要使用StoredDictionary
自然排序不是易于处理的事情。为实现此目的,Linq
包需要与OrderBy()
函数一起使用。
.OrderedBy()
需要使用IComparer
,在这种情况下,必须设计自定义
我很幸运地遇到了一篇文章,该文章专门针对带有数字的字符串的自然排序制作了自定义比较器。 A special thanks to James McCormack for this comparer.
首先,我已将scriptsPaths
字典转换为SortedDictionary。我还实例化organizedPaths
SortedDictionary。
public static IDictionary<string, List<string>> scriptsPaths = new SortedDictionary<string, List<string>>();
public static IDictionary<string, List<string>> organizedPaths = new SortedDictionary<string, List<string>>();
然后,一旦我的程序解析了子目录路径的目录,我就创建了一个名为NaturalSortComparer
的新类,其中我放置了从上面的链接找到的客户IComparer:
int IComparer<string>.Compare(string x, string y)
{
if (x == y)
return 0;
string[] x1, y1;
if (!table.TryGetValue(x, out x1))
{
x1 = Regex.Split(x.Replace(" ", ""), "([0-9]+)");
table.Add(x, x1);
}
if (!table.TryGetValue(y, out y1))
{
y1 = Regex.Split(y.Replace(" ", ""), "([0-9]+)");
table.Add(y, y1);
}
int returnVal;
for (int i = 0; i < x1.Length && i < y1.Length; i++)
{
if (x1[i] != y1[i])
{
returnVal = PartCompare(x1[i], y1[i]);
return isAscending ? returnVal : -returnVal;
}
}
if (y1.Length > x1.Length)
{
returnVal = 1;
}
else if (x1.Length > y1.Length)
{
returnVal = -1;
}
else
{
returnVal = 0;
}
return isAscending ? returnVal : -returnVal;
}
private static int PartCompare(string left, string right)
{
int x, y;
if (!int.TryParse(left, out x))
return left.CompareTo(right);
if (!int.TryParse(right, out y))
return left.CompareTo(right);
return x.CompareTo(y);
}
使用自定义比较器后,我现在将.OrderBy()
与自定义比较器
var organizedPaths = directoryManager
.ProcessDirectory(dbDirectory)
.OrderBy(x => x.Key, new NaturalSortComparer<string>());
在一个foreach循环到Console.WriteLine()键之后,我得到了我想要的顺序:
C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\0
C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\1
C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\2
C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\3
C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\4
C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\5
C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\6
C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\7
C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\8
C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\9
C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\10
C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\11
C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\12
最后一个注释我在SortedDictionary
上找到的每个资源都说明它们比Dictionary
更加耗费资源,所以请注意非常大的资源。但是,我只能希望我的文件夹结构不会增长太多,所以这对我来说是可以接受的。
答案 2 :(得分:-2)
请尝试以下操作:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string[] input = {
@"C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\0",
@"C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\1",
@"C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\10",
@"C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\11",
@"C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\12",
@"C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\2",
@"C:\Dev\FileResearch\ParseSqlConsole\DbScriptFolders\3"
};
Dictionary<string,List<int>> dict = input.GroupBy(x => x.Substring(0,x.LastIndexOf(@"\") + 1), y => int.Parse(y.Substring(y.LastIndexOf(@"\") + 1)))
.ToDictionary(x => x.Key, y => y.OrderBy(z => z).ToList());
}
}
}