Home > Software engineering >  Dynamic group by list data indexes
Dynamic group by list data indexes

Time:06-21

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.

  • Related