2

I have a data like

public class PermList
{
    public int UserId { get; set; }
    public int GroupId { get; set; }
    public int ModuleId { get; set; }
    public int BitMaskedPermission { get; set; }

    public List<PermList> TestData()
    {
        List<PermList> theList = new List<PermList>();
        PermList sample1 = new PermList {BitMaskedPermission = 15, GroupId = 3, ModuleId = 2, UserId = 1};
        theList.Add(sample1);
        PermList sample2 = new PermList { BitMaskedPermission = 2, GroupId = 3, ModuleId = 1, UserId = 1 };
        theList.Add(sample2);
        PermList sample3 = new PermList { BitMaskedPermission = 48, GroupId = 2, ModuleId = 2, UserId = 1 };
        theList.Add(sample3);
        return theList;
    }
}

enter image description here

I would like to apply OR to BitMaskedPermissions with grouping ModuleId. Here is what I would like to get;

enter image description here

How can I achieve this with using Linq.

TIA.

2 Answers 2

4

When you have an aggregation operation to perform that isn't one of the built-in ones (Sum, Max etc), you have to turn to Aggregate, which is more verbose but also much more powerful. Here, you want

var data = TestData();
var grouped = 
    from permList in data
    group permList by new { permList.UserId, permList.ModuleId } into g
    select new { // or a named class if you have one
        g.Key.UserId,
        g.Key.ModuleId,
        BitMaskedPermission 
            = g.Aggregate(0, (acc, curr) => acc | curr.BitMaskedPermission)
    };

Here, we pass Aggregate a function which takes the accumulator acc and the current value curr, and bitwise ORs them to get the ongoing accumulator value.

If you prefer the method-chaining syntax, it would look like (courtesy of @Chris):

var grouped = PermList.TestData()
    .GroupBy(x=> new{x.UserId, x.ModuleId})
    .Select(x=> new {
        x.Key.UserId, 
        x.Key.ModuleId, 
        mask = x.Aggregate(0, (acc, curr)=>acc|curr.BitMaskedPermission)}
     )
Sign up to request clarification or add additional context in comments.

6 Comments

And since I'd done the thing in the other form I present the method equivalent of that: PermList.TestData().GroupBy(x=> new{x.UserId, x.ModuleId}).Select(x=> new {x.Key.UserId, x.Key.ModuleId, mask = x.Aggregate(0, (acc, curr)=>acc|curr.BitMaskedPermission)}). Feel free to edit it into your answer if you want (or modify and edit or whatever
Also I think your Aggregate is wrong. You need g.Aggregate(0,(acc, curr) => acc | curr.BitMaskedPermission) I think (ie setting teh accumulator default to 0 and using the bitmask, not the PermList object.
@Chris thanks for the catch. btw if you are happy to use the first element of the sequence as the initial accumulator value (as we are here), you don't need to explicitly supply it.
Actually, I've just checked and you do need the initial accumulator. Without it uses the first element of the sequence but this is of course a PermList object whereas we need an int...
Although AakashM answer is correctly points the solution and a good explanation of aggregation, Chris' update is needed to solve the problem. Thanks both.
|
0

Maybe something like this:

PermList p=new PermList();
    var result= (
        from test in p.TestData()
        group test by new{test.UserId,test.ModuleId} into g
        select new
        {
            g.Key.UserId,
            g.Key.ModuleId,
            BitMaskedPermission= g.Sum (x =>x.BitMaskedPermission )
        }
    );

2 Comments

This would indeed work on the sample data, but suppose BitMaskedPermission were 15 for both the ModuleId 2 rows: this code would give 30, which would be wrong.
sum won't necessarily do what you want. If you have two bitmasks that are both 32 then the outcome of combining them should be 32, not 64 as sum would give.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.