我正在编写一个函数,它将采用某种输入数据结构(可能是一个DataTable;它仍然悬而未决,但重要的是它的结构在运行时才会被定义)并且分裂其中一个字符串列成为令牌列表。最终的结果将是一些数据结构(可能是一个词典,但同样,它仍然悬而未决),这将允许基于原始数据结构中的主键快速检索这些令牌列表。
通常你会使用一个元组作为复合键,但由于这是一个连接到数据库并获取任意表/查询的工具,我不能在这里采用这种方法。在我编写自己的CompoundKey类来处理这个问题之前,是否有适合这样做的内容在.NET中内置?这个应用程序中的某些地方会出现这种情况,而不仅仅是这种特殊的标记化功能。
这是一个非常粗略的概念,该方法将是什么样子,“对象”代表最终使用的复合键类。请注意,CompoundKey
类实际上并不存在(Word),WordBreakChars可以是string[]
或char[]
,也可以在班级的其他地方准备。
public Dictionary<object, string[]> SplitTokens(DataTable table, string split_column) {
Dictionary<object, string[]> Results = new Dictionary<object, string[]>();
DataColumn[] KeyCols = table.PrimaryKey;
if (KeyCols == null || KeyCols.Length == 0) {
throw new ArgumentException("DataTable has no primary key.");
}
foreach (DataRow row in table.Rows) {
string[] tokens = (row[split_column] as string ?? "").Split(WordBreakChars, StringSplitOptions.RemoveEmptyEntries);
CompoundKey key = new CompoundKey();
foreach (DataColumn col in KeyCols) {
key.Add(col.ColumnName, row[col]);
Results.Add(key, tokens);
}
}
return Results;
}
答案 0 :(得分:0)
在这种情况下,我会使用“键选择器”创建泛型函数。实际上,LINQ已经在.ToDictionary(
的一个重载中提供了这个,您可以将它与现有代码结合使用,以大大简化方法
public Dictionary<T, string[]> SplitTokens<T>(DataTable table, string split_column, Func<DataRow, T> keySelector)
{
Dictionary<T, string[]> Results;
Results = table.AsEnumerable().ToDictionary(keySelector,
row => (row[split_column] as string ?? "").Split(WordBreakChars, StringSplitOptions.RemoveEmptyEntries));
return Results;
}
现在调用者可以将他们想要的任何内容传递给keySelector
,这将是结果字典的强类型数据类型。
答案 1 :(得分:0)
这不是特别花哨,但似乎它会起作用。
public class CompoundKey : IEquatable<CompoundKey>, IEnumerable {
private object[] _Key;
private int _Hash;
private bool _Hashed;
//Dictionary keys need to be immutable. DO NOT expect sane behavior if you modify items inside the key.
public object this[int index] {
get { return _Key[index]; }
}
public CompoundKey(params object[] Key) {
_Key = Key;
_Hashed = false;
}
public static implicit operator CompoundKey(object[] Key) {
return new CompoundKey(Key);
}
public int Length { get { return _Key.Length; } }
public override int GetHashCode() {
if (!_Hashed) {
_Hash = 0;
foreach (object o in _Key) {
if (o != null) {
_Hash ^= o.GetHashCode();
}
}
}
return _Hash;
}
public bool Equals(CompoundKey other) {
if (other.GetHashCode() != _Hash) {
return false;
}
if (other.Length != this.Length) {
return false;
}
for (int i = 0; i < this.Length; i++) {
if (other[i] != this[i]) {
return false;
}
}
return true;
}
public override bool Equals(object obj) {
if (!(obj is CompoundKey)) {
return false;
}
return this.Equals((CompoundKey)obj);
}
public static bool operator ==(CompoundKey a, CompoundKey b) {
if ((object)a == null || (object)b == null) {
return false;
}
return a.Equals(b);
}
public static bool operator !=(CompoundKey a, CompoundKey b) {
return !(a == b);
}
public IEnumerator GetEnumerator() {
return _Key.GetEnumerator();
}
}
我添加了来自object[]
的隐式转换,因此可以简化用法,将object[]
直接输入字典。 (我知道我可以Linq离开使用.Select()
构建密钥数组的内部for循环;我现在只是为了更容易调试而使它更加明确。)
public Dictionary<CompoundKey, string[]> SplitTokens(DataTable table, string split_column) {
Dictionary<CompoundKey, string[]> Results = new Dictionary<CompoundKey, string[]>();
DataColumn[] key = table.PrimaryKey;
Regex RemoveIgnoredCharacters = new Regex("[" + Regex.Escape(Ignore) + "]");
char[] WordBreakChars = WordBreak.ToCharArray();
for (int i = 0; i < table.Rows.Count; i++) {
string split_value = RemoveIgnoredCharacters.Replace(table.Rows[i][split_column] as string ?? "", "");
string[] tokens = split_value.Split(WordBreakChars, StringSplitOptions.RemoveEmptyEntries);
object[] dictkey = new object[key.Length];
for (int j = 0; j < key.Length; j++) {
dictkey[j] = table.Rows[i][key[j].ColumnName];
}
Results.Add(dictkey, tokens);
}
return Results;
}