[英]Group A List Of object[] (Hopefully With Linq)
說我有一個相等尺寸的對象數組的集合,像這樣:
var rows = new List<object[]>
{
new object[] {1, "test1", "foo", 1},
new object[] {1, "test1", "foo", 2},
new object[] {2, "test1", "foo", 3},
new object[] {2, "test2", "foo", 4},
};
我想對一個或多個“列”進行分組-這些列將在運行時動態確定。 例如,按1、2和3列分組將導致三組:
當然,我可以通過某種自定義組類以及排序和迭代來實現。 但是,看起來我應該可以使用Linq分組更干凈地進行此操作。 但是我的臨q夫使我失望。 有任何想法嗎?
如果您知道前面的分組列,則@Matthew Whited的解決方案很好。 但是,聽起來您需要在運行時確定它們。 在這種情況下,您可以創建一個相等比較器,該比較器使用可配置的列集為GroupBy
定義行相等:
rows.GroupBy(row => row, new ColumnComparer(0, 1, 2))
比較器檢查每個指定列的值是否相等。 它還結合了每個值的哈希碼:
public class ColumnComparer : IEqualityComparer<object[]>
{
private readonly IList<int> _comparedIndexes;
public ColumnComparer(params int[] comparedIndexes)
{
_comparedIndexes = comparedIndexes.ToList();
}
#region IEqualityComparer
public bool Equals(object[] x, object[] y)
{
return ReferenceEquals(x, y) || (x != null && y != null && ColumnsEqual(x, y));
}
public int GetHashCode(object[] obj)
{
return obj == null ? 0 : CombineColumnHashCodes(obj);
}
#endregion
private bool ColumnsEqual(object[] x, object[] y)
{
return _comparedIndexes.All(index => ColumnEqual(x, y, index));
}
private bool ColumnEqual(object[] x, object[] y, int index)
{
return Equals(x[index], y[index]);
}
private int CombineColumnHashCodes(object[] row)
{
return _comparedIndexes
.Select(index => row[index])
.Aggregate(0, (hashCode, value) => hashCode ^ (value == null ? 0 : value.GetHashCode()));
}
}
如果您經常這樣做,則可以將其放在擴展方法后面:
public static IGrouping<object[], object[]> GroupByIndexes(
this IEnumerable<object[]> source,
params int[] indexes)
{
return source.GroupBy(row => row, new ColumnComparer(indexes));
}
// Usage
row.GroupByIndexes(0, 1, 2)
擴展IEnumerable<object[]>
僅適用於.NET4。您需要直接在.NET 3.5中擴展List<object[]>
。
如果您的集合包含帶有索引器的項目(例如您的object[]
,則可以這樣操作...
var byColumn = 3;
var rows = new List<object[]>
{
new object[] {1, "test1", "foo", 1},
new object[] {1, "test1", "foo", 2},
new object[] {2, "test1", "foo", 3},
new object[] {2, "test2", "foo", 4},
};
var grouped = rows.GroupBy(k => k[byColumn]);
var otherGrouped = rows.GroupBy(k => new { k1 = k[1], k2 = k[2] });
...如果您不喜歡上面的靜態集,則也可以直接在LINQ中做一些更有趣的事情。 這將假定您的HashCodes將適用於Equals評估。 注意,您可能只想編寫IEqualityComparer<T>
var cols = new[] { 1, 2};
var grouped = rows.GroupBy(
row => cols.Select(col => row[col])
.Aggregate(
97654321,
(a, v) => (v.GetHashCode() * 12356789) ^ a));
foreach (var keyed in grouped)
{
Console.WriteLine(keyed.Key);
foreach (var value in keyed)
Console.WriteLine("{0}|{1}|{2}|{3}", value);
}
最短的解決方案:
int[] columns = { 0, 1 };
var seed = new[] { rows.AsEnumerable() }.AsEnumerable(); // IEnumerable<object[]> = group, IEnumerable<group> = result
var result = columns.Aggregate(seed,
(groups, nCol) => groups.SelectMany(g => g.GroupBy(row => row[nCol])));
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.