我有以下代码:
string[] tokens; //columns which I want to groupBy (e.g., storeID, location)
Dictionary<string, List<DataRow>> dictShort = null; // what I want to return
switch (tokens.Length)
{
case 1:
dictShort = dsShort.Tables[0].AsEnumerable()
.GroupBy(x => x[block])
.Where(g => exp.GroupSizeOk((uint)g.Count()))
.OrderBy(g => g.Count())
.ToDictionary(g => g.Key.ToString(), g => g.ToList());
break;
case 2:
dictShort = (Dictionary<string, List<DataRow>>)
dsShort.Tables[0].AsEnumerable()
.GroupBy(x => x[tokens[0]], x => x[tokens[1]])
.Where(g => exp.GroupSizeOk((uint)g.Count()))
.OrderBy(g => g.Count())
.ToDictionary(g => g.Key.ToString(), g => g.ToList());
// NOT COMPILING> cannot convert Dictionary<string, List<objet>>
// to Dictionary<string, List<DataRow>>
break;
case 3:
dictShort = (Dictionary<string, List<DataRow>>)
dsShort.Tables[0].AsEnumerable()
.GroupBy(x => new { x[tokens[0]], x[tokens[1]], x[tokens[2]]})
.Where(g => exp.GroupSizeOk((uint)g.Count()))
.OrderBy(g => g.Count())
.ToDictionary(g => g.Key.ToString(), g => g.ToList());
// NOT COMPILING: invalid anonymous type member declarator
break;
}
我的问题:
(1)案例3不起作用,我该如何纠正?
(2)我可以让这个动态吗? (即,foreach或类似的东西,以便它适用于任意数量的colunms)
public bool GroupSizeOk(UInt32 size)
{
return (size >= _minGroupSize)
&& (_maxGroupSize > 0 ? size <= _maxGroupSize : true);
}
答案 0 :(得分:1)
您需要的是数组的IEqualityComparer
,它将根据数组中的项比较数组,而不是数组本身的引用。这样的比较器很简单,可以创建:
public class SequenceComparer<T> : IEqualityComparer<IEnumerable<T>>
{
private IEqualityComparer<T> itemComparer;
public SequenceComparer(IEqualityComparer<T> itemComparer = null)
{
this.itemComparer = itemComparer ?? EqualityComparer<T>.Default;
}
public bool Equals(IEnumerable<T> x, IEnumerable<T> y)
{
return x.SequenceEqual(y);
}
public int GetHashCode(IEnumerable<T> obj)
{
unchecked
{
return obj.Aggregate(79,
(hash, next) => hash * 39 + next.GetHashCode());
}
}
}
现在,您的查询基本上可以按照您的预期工作,另一个关键更改是将数组tokens
转换为表示给定数组中该行的值的数组:
var dictShort = dsShort.Tables[0].AsEnumerable()
.GroupBy(row => tokens.Select(token => row[token]).ToArray(),
new SequenceComparer<object>())
.Where(g => exp.GroupSizeOk((uint)g.Count()))
.OrderBy(g => g.Count())
.ToDictionary(g => string.Join(", ", g.Key), g => g.ToList());
答案 1 :(得分:-1)
你有:
.GroupBy(new x => { x[tokens[0]], x[tokens[1]], x[tokens[2]]})
但它应该是:
.GroupBy(x => string.Join(",",new [] { x[tokens[0]], x[tokens[1]], x[tokens[2]]}))
在我意识到这是你答案的一部分之前,我已经改变了你的问题。新的内容属于lambda。
至于根据列使代码动态化,是的,你可以。
.GroupBy(x => string.Join(",",tokens.Where(w => w.Columns.Contains(w)).Select(s => x[s]).ToArray()))
这应该为您提供数组中所有匹配列的分组。
答案 2 :(得分:-1)
我刚刚找到答案:
dictShort = dsShort.Tables[0].AsEnumerable()
// This where selects elements if and only if all fields are not null
.Where(x => ListAnd(tokens.Select(t => x[t] != DBNull.Value && IsFilledIn(x[t].ToString())).ToArray()))
.GroupBy(x => String.Join("+", tokens.Select(t => x[t].ToString()).ToArray()))
//.GroupBy(x => x[block]) // TODO
.Where(g => exp.GroupSizeOk((uint)g.Count()))
.OrderBy(g => g.Count())
.ToDictionary(g => g.Key/*.ToString()*/, g => g.ToList());