简体   繁体   中英

C# List grouping and assigning a value

I have a list of Orders. This list contains multiple orders for the same item, see the table below.

I then want to assign each item that is the same (ie ABC) the same block ID. So ABC would have a block ID of 1 & each GHJ would have a block ID of 2 etc. What is the best way of doing this?

Currently I order the list by Order ID and then have a for loop and check if the current Order ID is equal to the next Order ID if so assign the two the same block ID. Is there a better way of doing this using linq or any other approach?

Order ID             Block ID

ABC 
ABC
ABC
GHJ
GHJ
GHJ
MNO
MNO

You can do this that way, it will assign same blockid for same orderid

var ordered = listOrder.GroupBy(x => x.OrderId).ToList();
for (int i = 0; i < ordered.Count(); i++)
{
    ordered[i].ForEach(x=>x.BlockId=i+1);
}   

it will group orders by orderid then assign each group next blockid. Note that it won't be done fully in linq, because linq is for querying not changing data.

Always depends of what better means for you in this context.

There are a bunch of possible solutions to this trivial problem.
On top of my head, I could think of:

var blockId = 1;
foreach(var grp in yourOrders.GroupBy(o => o.OrderId))
{
    foreach(var order in grp)
    {
        order.BlockId = blockId;
    }
    blockId++;
}

or (be more "linqy" ):

foreach(var t in yourOrders.GroupBy(o => o.OrderId).Zip(Enumerable.Range(1, Int32.MaxValue), (grp, bid) => new {grp, bid}))
{
    foreach(var order in t.grp)
    {
        order.BlockId = t.bid;
    }
}

or (can you still follow the code?):

var orders = yourOrders.GroupBy(o => o.OrderId)
                       .Zip(Enumerable.Range(1, Int16.MaxValue), (grp, id) => new {orders = grp, id})
                       .SelectMany(grp => grp.orders, (grp, order) => new {order, grp.id});
foreach(var item in orders)
{
    item.order.BlockId = item.id;
}

or (probably the closest to a simple for loop):

Order prev = null;
blockId = 1;
foreach (var order in yourOrders.OrderBy(o => o.OrderId))
{
    order.BlockId = (prev == null || prev.OrderId == order.OrderId) ?
                    blockId :
                    ++blockId;
    prev = order;
}

Linq? Yes.
Better than a simple loop? Uhmmmm....


Using Linq will not magically make your code better . Surely, it can make it often more declarative/readable/faster (in terms of lazy evaluation), but sure enough you can make otherwise fine imperative loops unreadable if you try to force the use of Linq just because Linq.


As a side note:
if you want to have feedback on working code, you can ask at codereview.stackexchange.com

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM