在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,列表的实际物理顺序无关紧要,只是属性已更改。
项目数量不仅仅改变了“订单”。
实现这一目标的最简单方法是什么?
答案 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)
我们必须区分向上(向末尾)向下移动元素(到列表的开头)。我们定义两个订单号i
和k
,其中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();
}
}
}