Click here to Skip to main content
15,888,351 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
My data starts in a JSON object:
JSON
    {"page":"1",
     "per_page":10,
     "total":100,
     "total_pages":10,
     "data":[{"id":1,
              "userId":1,
              "userName":"Jim Silver", 
              "timestamp":16425382171,
              "txnType":"debit",
              "amount":"$1,000.07",
              "location":{"id":2,
                          "address":"654, Somewhere, Some Street", 
                          "city":"Some City",
                          "zipCode":12345},
                          "ip":"202.210.105.105"},
             {"id":2," ...}
             {"id":3," ...}
              ...
             {"id":n," ...}]


I need to get the user ID and amount into a List<list<int>> which I've done here:

C#
var model = JsonConvert.DeserializeObject<TxnResponse>(rawJSON);
var elements = model.data;

List<List<int>> userTxns = new List<List<int>>(elements.Count);
List<int> record = null;

int userID = 0;
int userAmount = 0;

for (int row = 0; row < elements.Count; row++)
{
    userID = elements[row].userId;
    userAmount = Convert.ToInt32(Math.Floor(decimal.Parse(model.data[row].amount, System.Globalization.NumberStyles.Currency)));

    record = new List<int>();
    record.Add(userID);
    record.Add(userAmount);

    userTxns.Add(record);
}

return userTxns.GroupBy();


The result should look like this when printed to screen (Console.WriteLine(String.Join("\n", list.Select(x => String.Join(" ", x))));):
1 1000
2 2000
3 3000
4 4000

Without the Group By, if the JSON object has 10 data items, I have 10 (userId, amount) records.

Model:

C#
public class TxnResponse
{
    public string page { get; set; }
    public int per_page { get; set; }
    public int total { get; set; }
    public int total_pages { get; set; }
    public List<data> data { get; set; }
}


public class data
{
    public int id { get; set; }
    public int userId { get; set; }
    public string userName { get; set; }
    public object timestamp { get; set; }
    public string txnType { get; set; }
    public string amount { get; set; }
    public Location location { get; set; }
    public string ip { get; set; }
}

public class Location
{
    public int LocationID { get; set; }
    public string Address { get; set; }
    public string City { get; set; }
    public int ZipCode { get; set; }
}

How do I do GroupBy on user ID? Thank you.

What I have tried:

C#
return userTxns.GroupBy(userID);
return userTxns.GroupBy(u => userID);


but get "the type arguments for method cannot be inferred from the usage..." or "Cannot implicitly convert type...".
Posted
Updated 1-Apr-20 9:27am
Comments
Richard Deeming 1-Apr-20 12:09pm    
Based on the sample data, your List<List<int>> will already provide the output you've said you want.

What are you trying to group by, and what output are you expecting?
Member 12338931 1-Apr-20 13:19pm    
I'm trying to group by userId in the userTxns object which contains lists of userIDs and amounts.

The output should group userIds and sum each user's amounts like this:

1 1000
2 2000
3 3000
4 4000

where the first column is the userId and the second column is each respective user's summed amounts.

If you want to stick with the List<List<int>> approach, grouping by the first value and summing the second, something like this should work:
C#
return userTxns.GroupBy(u => u[0], (key, values) => new List<int> 
{ 
    key, 
    values.Select(l => l[1]).Sum() 
}).ToList();
Personally, I'd be inclined to use a dictionary instead:
C#
var model = JsonConvert.DeserializeObject<TxnResponse>(rawJSON);
var result = new Dictionary<int, int>(elements.Count);
foreach (data item in model.data)
{
    int userId = item.userId;
    int userAmount = Convert.ToInt32(Math.Floor(decimal.Parse(item.amount, System.Globalization.NumberStyles.Currency)));
    
    if (result.TryGetValue(userId, out int existingAmount))
    {
        userAmount += existingAmount;
    }
    
    result[userId] = userAmount;
}

return result;
 
Share this answer
 
v2
Comments
Maciej Los 1-Apr-20 15:46pm    
5ed!
Member 12338931 1-Apr-20 16:13pm    
Thanks. I'm getting the following error in the values.Select ... line:

Error CS0266 Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<system.collections.generic.list<int>>' to 'System.Collections.Generic.List<system.collections.generic.list<int>>'. An explicit conversion exists (are you missing a cast?)

Google-ing/searching how to perform cast (if required). If you see if/what's causing the error, could you post response?

Yes, Dictionary might be better but I've got to return a List<List<int>>. Thanks.
Richard Deeming 1-Apr-20 18:59pm    
Just add .ToList() to the end:
return userTxns.GroupBy(...).ToList();
Member 12338931 1-Apr-20 21:09pm    
That was it. Thank you very much.
GroupBy doesn't return the records - it returns groups of records, which are (basically) in (key, value) pairs.

Have a look at this: Using Linq to create a Dictionary of sub-Lists by grouping from a collection.[^] It was written to group a days worth of logs together, but it'll work the same for IDs and return a Dictionary of Lists - one list for each ID value - with a minor change to the grouping clause.
 
Share this answer
 
Comments
Member 12338931 1-Apr-20 13:31pm    
Thanks ... I'll see if I can figure out how to implement this...
Member 12338931 1-Apr-20 13:40pm    
So in your example, are all the example log files in the rawFiles object as in

Dictionary<string, list<string="">> groups = rawFiles.GroupBy(r => GetDateFromPath(r)).ToDictionary(g => g.Key, g => g.ToList());
Member 12338931 1-Apr-20 13:50pm    
Also, the method must return a List<list<int>>.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900