简体   繁体   中英

Rearrange generic list after sequence update in c#

Let's say I have a generic List such as this:

var categories = new List<Category>() {
    new Category() { sequence = 3, categoryName = "Category F" },
    new Category() { sequence = 1, categoryName = "Category S" },
    new Category() { sequence = 2, categoryName = "Category Z" },
    new Category() { sequence = 4, categoryName = "Category X" },
    new Category() { sequence = 5, categoryName = "Category V" }
};

I'm trying to replace the given sequence number with another ie update item in the list with sequence# 2 with number 5 as below:

int currSeq = 2;
int newSeq = 5;
var item = categories.Find(a => a.sequence == currSeq);
item.sequence = newSeq;

If the newSeq were not become duplicate eg newSeq = 6, I could just do OrderBy:

categories = categories.OrderBy(c => c.sequence).ToList();

But the problem is when they become duplicates, I need the newSeq become in sequence# 5 and bump the other duplicated sequence# 5 + 1.

Please help with any guidance solving this. Thanks.

Update: certain cases when new sequence < old sequence, the output is not as desired.

Scenario A:

var categories = new List<Category>() {
    new Category() { sequence = 3, categoryName = "Category F" },
    new Category() { sequence = 1, categoryName = "Category S" },
    new Category() { sequence = 2, categoryName = "Category Z" },
    new Category() { sequence = 5, categoryName = "Category X" },
    new Category() { sequence = 6, categoryName = "Category V" }
};
int currSeq = 2;
int newSeq = 1;
var result = categories.UpdateSequence(currSeq,newSeq).OrderBy(x=>x.sequence);

Output Scenario A:

1: Category S
3: Category Z
4: Category F
5: Category X
6: Category V

Desired Output Scenario A:

1: Category Z
2: Category S
3: Category F
5: Category X
6: Category V

Scenario B:

int currSeq = 3;
int newSeq = 1;
var result = categories.UpdateSequence(currSeq,newSeq).OrderBy(x=>x.sequence);

Output Scenario B:

1: Category Z
2: Category S
4: Category F
5: Category X
6: Category V

Desired Output Scenario B:

1: Category F
2: Category S
3: Category Z
5: Category X
6: Category V

Do what elgonzo said in his comment. Plus start out with widely spaced sequence numbers, ie 1000, 2000, 3000 rather than 1,2,3. I don't know your use case, but unless you are reordering a lot, this will minimize the number of "bumps" of sequence numbers you have to do.

Assuming that you have sorted the list based on the Sequence already, you can use the FindIndex method of LINQ to find the index of element with currSeq and newSeq and then use RemoveAt along with Insert to place the updated element at correct position.

Something like this:

int currSeq = 2;
int newSeq = 5;
var oldIndex = categories.FindIndex(i => i.Sequence == currSeq);
var newIndex = categories.FindIndex(i => i.Sequence == newSeq);

if(oldIndex > -1)
{
    var oldItem = lst[oldIndex];
    oldItem.ID = newSeq;

    if(newIndex > -1)
    {
        newIndex = newIndex-1 < 0 ? 0 : newIndex - 1;    //in case the first element is the existing one
        categories.RemoveAt(oldIndex);
        categories.Insert(newIndex, oldItem);
    }
    else
    {
        categories = lst.OrderBy(i => i.ID).ToList();
    }
}

I think this will solve your issue. But when inserting all following lines are moved too. Is this okay for you?

    var categories = new List<Category>() {
        new Category() { sequence = 3, categoryName = "Category F" },
        new Category() { sequence = 1, categoryName = "Category S" },
        new Category() { sequence = 2, categoryName = "Category Z" },
        new Category() { sequence = 4, categoryName = "Category X" },
        new Category() { sequence = 5, categoryName = "Category V" }
    };

    List<string> list = new List<string>();
    for (int i = 0; i < 6; i++)
    {
        list.Add("");
    }

    foreach (var item in categories)
    {
        list[item.sequence] = item.categoryName;
    }

    var removeFrom = 2;
    var removeTo = 5;

    list.Insert(removeTo, list[removeFrom]);
    list.RemoveAt(removeFrom);

Update based on comment and Edited OP.

Assuming your Category class is defined as following.

public class Category
{
    public int sequence{get;set;}
    public string categoryName{get;set;}
}

You can write the Update Sequence method as follows to get the desired result when newValue < oldValue.

 public static List<Category> UpdateSequence(this List<Category> categories, int oldValue,int newValue)
 {
        var invalidState = -1;
        if(oldValue>newValue)
        {
            categories.Single(x=>x.sequence == oldValue).sequence = invalidState;
            if(categories.Any(x=>x.sequence == newValue))
            {
                categories = UpdateSequence(categories, newValue,newValue+1);
            }
            categories.Single(x=>x.sequence == invalidState).sequence = newValue;
        }
        else
        {
            if(categories.Any(x=>x.sequence == newValue))
            {
                categories = UpdateSequence(categories, newValue,newValue+1);
            }
            categories.Single(x=>x.sequence==oldValue).sequence = newValue;
        }
        return categories;
    }

Input

var categories = new List<Category>() {
    new Category() { sequence = 3, categoryName = "Category F" },
    new Category() { sequence = 1, categoryName = "Category S" },
    new Category() { sequence = 2, categoryName = "Category Z" },
    new Category() { sequence = 5, categoryName = "Category X" },
    new Category() { sequence = 6, categoryName = "Category V" }

Scenario 1:

int currSeq = 2;
int newSeq = 1;
var result = categories.UpdateSequence(currSeq,newSeq).OrderBy(x=>x.sequence);

Output

1 Category Z 
2 Category S 
3 Category F 
5 Category X 
6 Category V 

Scenario 2

int currSeq = 3;
int newSeq = 1;
var result = categories.UpdateSequence(currSeq,newSeq).OrderBy(x=>x.sequence);

Ouput

1 Category F 
2 Category S 
3 Category Z 
5 Category X 
6 Category V 

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