0

I am updating the property of the list items.

class Response
{
    public string Name { get; set; }
    public int Order { get; set; }
}

Here I want to update the Order of a List<Response> variable. As of now, I am looping through each item of the list and updating it.

List<Response> data = FromDb();
foreach (var item in data)
{
    if(item.Name.Equals("A"))
    {
       item.Order=1;
    }
    if(item.Name.Equals("B"))
    {
       item.Order=2;
    }
    //Like this I have arround 20 conditions
}

The above code is working fine, but the problem is the Cognitive Complexity of the method is more than the allowed.

I tried something like below

data.FirstOrDefault(x => x..Equals("A")).Order = 1;
data.FirstOrDefault(x => x..Equals("B")).Order = 2;
//and more ...

In this code also null check is not in place, So if the searching string is not present in the list then again it will break.

If I add null check condition then again the complexity getting higher.

So here I want without any for loop or if, If I can update the Order of the list by using linq/lamda or anything else.

Tufan Chand
  • 692
  • 4
  • 19
  • 36
  • There will always be a `for` loop somewhere if you are working with multiple items. LINQ does not mutate objects, so while you might be able to do that it won't be idiomatic. – Tanveer Badar Mar 19 '20 at 14:38
  • 2
    `Dictionary` looks more natural than `List` in this case, if you need to search by key – Renat Mar 19 '20 at 14:39
  • 1
    Does this answer your question? [Update all objects in a collection using LINQ](https://stackoverflow.com/questions/398871/update-all-objects-in-a-collection-using-linq) – Lucifer Mar 19 '20 at 14:39
  • 1
    I don’t know the purpose of that Response class but is it okay to use Enum for your Name attribute so that you can have order automatically if you start your Enum with A which have value of 1? – Ardahan Kisbet Mar 19 '20 at 14:43
  • @Lucifer. I went to this link sometimes back, I am unable to add any condition with the answer which is my primary requirement. – Tufan Chand Mar 19 '20 at 14:43
  • @ArdahanKisbet. the return type of the method is the list of response and even some other properties are part of that response class. – Tufan Chand Mar 19 '20 at 14:47
  • @TufanChand Are indicies of Order somewhat permanent. I mean does A always mean Order 1, B Order 2 on so on. In other words is the alphabetical number connected with index or you can have name "G" for example with order "948423"? – Leron Mar 19 '20 at 14:49
  • @Leron_says_get_back_Monica. The Name and Order combinations are permanent, but not related with any index the value "A", "B" I just have given for demo purpose the real values are different – Tufan Chand Mar 19 '20 at 14:53
  • @TufanChand, does this order value comes from DB or a static value? If it comes from DB, you can join with the Order list. – SelvaS Mar 19 '20 at 14:55
  • @SelvaS. "Order" is not from DB. Only the Names are coming from DB. – Tufan Chand Mar 19 '20 at 14:58
  • @TufanChand Then Dictionary makes the most sense. `Dictionary indexByName = new Dictionary () { {"A", 1}, {"B", 2}}` and so on. Then `foreach (var item in data) { item.Order = indexByName[item.Name] }`; – Leron Mar 19 '20 at 14:58

1 Answers1

3

I don't know how you measure Cognitive Complexity and how much of it is allowed to be pushed out into other functions, but something like this makes the ordering quite declarative?

[Fact]
public void TestIt()
{
    var data = FromDb().Select(SetOrder(
        ("A", 1),
        ("B", 2)
    ));
}

static Func<Response, Response> SetOrder(params (string Name, int Order)[] orders)
{
    var orderByKey = orders.ToDictionary(x => x.Name);

    return response =>
    {
        if (orderByKey.TryGetValue(response.Name, out var result))
            response.Order = result.Order;

        return response;
    };
}

Addendum in response to comment:

In order to have a default value for unmatched names, the SetOrder could be changed to this:

static Func<Response, Response> SetOrder(params (string Name, int Order)[] orders)
{
    var orderByKey = orders.ToDictionary(x => x.Name);

    return response =>
    {
        response.Order = 
            orderByKey.TryGetValue(response.Name, out var result)
                ? result.Order
                : int.MaxValue;

        return response;
    };
}
asgerhallas
  • 16,890
  • 6
  • 50
  • 68
  • If I want to set a default order which is not in my static list. For example, if Name="Z" came from DB and I don't have any static order for this text So I want to assign a very higher Order like 9999 so that it will come at last of the list. – Tufan Chand Mar 20 '20 at 08:58