I want to group by dynamically according to more than one index in a list.
Model
public class MyModel
{
public string baseTableName { get; set; }
public List<object> columns { get; set; }
public List<List<object>> rows { get; set; }
}
I need to find the indexes of the pk columns list in this model. Then I want to group the data in the rows list by pk columns.
Sample Request
{
"tableName": "fooTable",
"columns": [
"c1",
"c2",
"c3"
],
"rows": [
[
"1",
"a",
"kobe"
],
[
"2",
"a",
"lebron"
]
]
}
In this sample request, columns c1 and c2 are pk.
Codes
// Returns indexes of pk columns.
var pkColumnIndexes = GetPkIndexes(columns);
var gp = requestObject.rows.GroupBy(gp => new { indx1 = gp[pkColumnIndexes[0]], indx2 = gp[pkColumnIndexes[1]] });
var groupData = gp.Select(s => s.LastOrDefault()).ToList();
--
(gp => new { indx1 = gp[pkColumnIndexes[0]], indx2 = gp[pkColumnIndexes[1]] })
I want to group this part according to indexes.
Can group by keys dynamically created with a for loop?
CodePudding user response:
Using an IEqualityComparer
for sequences, you can create sequence keys and group by them:
public static class Make {
public static IEqualityComparer<IEnumerable<T>> IESequenceEqual<T>() => new IEnumerableSequenceEqualityComparer<T>();
public static IEqualityComparer<IEnumerable<T>> IESequenceEqual<T>(T _) => new IEnumerableSequenceEqualityComparer<T>();
private class IEnumerableSequenceEqualityComparer<T> : IEqualityComparer<IEnumerable<T>> {
public bool Equals(IEnumerable<T> x, IEnumerable<T> y) =>
Object.ReferenceEquals(x, y) || (x != null && y != null && (x.SequenceEqual(y)));
public int GetHashCode(IEnumerable<T> items) {
// Will not throw an OverflowException
//unchecked {
// return items.Where(e => e != null).Select(e => e.GetHashCode()).Aggregate(17, (a, b) => 23 * a b);
//}
var hc = new HashCode();
foreach (var item in items)
hc.Add(item);
return hc.ToHashCode();
}
}
}
var IEObjSeqEq = Make.IESequenceEqual<string>();
var ans = requestObject.rows.GroupBy(r => pkColumnIndexes.Select(idx => r[idx].ToString()), IEObjSeqEq);
Note you must explicitly convert to string
to avoid the default reference equality of object
.