2

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?

anıl yıldırım
  • 953
  • 1
  • 10
  • 17
  • C# is a language of types. What type do you imagine your group `Key` will be? – NetMage Jun 20 '22 at 19:42
  • You can use the techniques in [this answer](https://stackoverflow.com/a/59079605/2557128), simplified since you know you are working with strings. – NetMage Jun 20 '22 at 19:47
  • Your class uses `object` for its base elements, and your JSON isn't C# so not helpful - what is the actual runtime type of the elements in e.g. `columns`? – NetMage Jun 20 '22 at 20:33

1 Answers1

1

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.

NetMage
  • 26,163
  • 3
  • 34
  • 55