3

考虑具有 int 属性 Order 的 List 中的 4 个(最多 100 个)类 A 的实例。

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

注意这是一个列表,列表的实际物理顺序无关紧要,只是属性发生了变化。

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

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

4

6 回答 6

7

你可以这样做:

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 );
于 2013-06-15T14:38:56.560 回答
7

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

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

于 2013-06-15T14:43:08.707 回答
3

We have to differentiate between moving an element upwards (to the end) or downwards (to the beginning of the list). Let's define two order numbers i and k where i < k.

Move element i upwards to k:
The orders below i and above k are not affected.
The orders i+1 ... k are decreased by one and i becomes k.

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;

Move element k downwards to i:
The orders below i and above k are not affected.
The orders i ... k-1 are increased by one and k becomes i.

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;
于 2013-06-15T14:51:26.363 回答
1

如果你能负担得起,我会给它们编号,并在两者之间留出空隙:

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

这样,您可以通过在 gab 中选择一个数字来简单地重新排序。

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

经过一些迭代后,您可能在某个插入点处没有任何间隙。使用 100 件商品,您可以简单地重置所有订单号以再次获得相同的数量。

于 2013-06-15T14:12:42.933 回答
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();
        }
    }
}
于 2013-06-15T15:17:15.080 回答
0

Could you just keep the items in a list and imply the Order property from the physcial order of the items in the list?

Given an Item class without an order property, like so:

class Item
{
    public readonly string Value;

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

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

You could write a simple collection class for Items which has a Move() method to let you move an item from one index to another:

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();
    }
}

You can use Items like so:

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.

Then when you need the Order you can synthesize it from the list's physical order like so:

var orderedItems = items.Select((item, index) => new { Item = item, Order = index});
于 2013-06-15T14:54:34.783 回答