最简单的方法来重新排序序列

时间:2013-06-15 13:57:06

标签: c# linq

在List中考虑4个(比如说多达100个)A类实例,它具有int属性Order。

a0.Order is 0
a1.Order is 1
a2.Order is 2
a3.Order is 3

现在需要更改Order属性,以便在a3之前插入a0(或在列表中的任何索引处插入 - 可以在开始,结束或中间。)

结果应该是这样的:

a0.Order is 2
a1.Order is 0
a2.Order is 1
a3.Order is 3

请注意,这是一个List,列表的实际物理顺序无关紧要,只是属性已更改。

项目数量不仅仅改变了“订单”。

实现这一目标的最简单方法是什么?

6 个答案:

答案 0 :(得分:4)

Order属性不应该是整数而是小数。您可以轻松更改值,然后按其排序以按任意顺序检索项目。新值是前一个值和后一个值之间的中点。

P.S。然后,您只需要更改要重新定位的列表中项目的Order属性。

答案 1 :(得分:2)

你可以这样做:

void MoveAndUpdateOrder(List<A> list, A item, int positionToInsert)
{
    // Order elements
    var ordered_list = list.OrderBy(a => a.Order).ToList();

    // Remove and insert at the proper position
    ordered_list.Remove(item);
    ordered_list.Insert(positionToInsert, item);

    // Update the Order properties according to it's current index
    for ( int i = 0; i < ordered_list.Count; i++ )
        ordered_list[i].Order = i;
}

然后像这样称呼它:

var a0 = new A { Order = 0 };
var a1 = new A { Order = 1 };
var a2 = new A { Order = 2 };
var a3 = new A { Order = 3 };

var list = new List<A>
{
    a0, a1, a2, a3
};

MoveAndUpdateOrder( list, a0, 2 );

答案 2 :(得分:1)

如果你能负担得起,我会用它们之间的间隙编号:

a0.Order is 10
a1.Order is 20
a2.Order is 30
a3.Order is 40

通过这种方式,您可以通过在瞎扯中选择一个数字来进行简单的重新排序。

a0.Order is 35
a1.Order is 20
a2.Order is 30
a3.Order is 40

经过一些迭代后,您可能在某个插入点处没有留下任何碎片。使用100个项目,您可以简单地重置所有订单号,以便再次获得相同的点数。

答案 3 :(得分:1)

我们必须区分向上(向末尾)向下移动元素(到列表的开头)。我们定义两个订单号ik,其中i < k

将元素i向上移动到k
i以上k以下的订单不受影响 订单i+1 ... k减1,i变为k

将元素k向下移动到i
i以上k以下的订单不受影响 订单i ... k-1增加1,k变为i

向上移动:

A moving = list.Where(a => a.Order == i);
foreach (A x in list.Where(a => a.Order > i && a.Order <= k)
{
    x.Order--;
}
moving.Order = k;

向下移动:

A moving = list.Where(a => a.Order == k);
foreach (A x in list.Where(a => a.Order >= i && a.Order < k)
{
    x.Order++;
}
moving.Order = i;

答案 4 :(得分:0)

您是否可以将这些项目保留在列表中,并从列表中项目的物理顺序中隐含Order属性?

给定Item没有订单属性,如下所示:

class Item
{
    public readonly string Value;

    public Item(string value)
    {
        Value = value;
    }

    public override string ToString()
    {
        return Value;
    }
}

您可以为Items编写一个简单的集合类,它具有Move()方法,可以让您将项目从一个索引移动到另一个索引:

class Items: IEnumerable<Item>
{
    private readonly List<Item> _items = new List<Item>();

    public void Add(Item item)
    {
        _items.Add(item);
    }

    public int Count
    {
        get { return _items.Count; }
    }

    public void Move(int oldIndex, int newIndex)
    {
        Item item = _items[oldIndex];
        _items.RemoveAt(oldIndex);
        _items.Insert(newIndex, item);
    }

    IEnumerator<Item> IEnumerable<Item>.GetEnumerator()
    {
        return _items.GetEnumerator();
    }

    public IEnumerator GetEnumerator()
    {
        return _items.GetEnumerator();
    }
}

你可以这样使用Items

var items = new Items
{
    new Item("a0"),
    new Item("a1"),
    new Item("a2"),
    new Item("a3")
};

// ...

items.Move(0, 2); // Move the item at index 0 to index 2.

然后当您需要Order时,您可以从列表的物理顺序中合成它,如下所示:

var orderedItems = items.Select((item, index) => new { Item = item, Order = index});

答案 5 :(得分:0)

我为你编写了算法,它使用了排序和LinkedList集合:

using System;
using System.Collections.Generic;

namespace OrderExample {

    public class A {
        public int Order { get; set; } 
    }

    public class Program {

        // Change order so that a is ordered between b and c.
        public static void SetOrder(List<A> list, A a, A b, A c) {
            list.Sort((x, y) => x.Order.CompareTo(y.Order));
            var linkedList = new LinkedList<A>(list);
            var bNode = linkedList.Find(b);
            if (bNode != null) {
                linkedList.Remove(a);
                linkedList.AddAfter(bNode, a);
                var i = 0;
                foreach (var value in linkedList) {
                    value.Order = i++;
                }                
            }
        }

        static void Main() {
            var a0 = new A {Order = 0};
            var a1 = new A {Order = 1};
            var a2 = new A {Order = 2};
            var a3 = new A {Order = 3};
            var list = new List<A> {a0, a1, a2, a3};

            SetOrder(list, a0, a2, a3);
            foreach (var a in list) {
                Console.Out.WriteLine(a.Order);
            }
            Console.ReadKey();
        }
    }
}