鉴于下面的测试用例,我如何:
- 对
IList<TestObject>
进行排序基于一个匹配的索引Id
在IList<int>
列表。 - 不匹配的值被移动到列表的末尾并按其原始索引排序。在这种情况下,由于索引列表中不存在 3 和 4,我们希望看到
list[3] == 3
和list[4] == 4
. - 虽然我知道这可以通过 linq 实现,但我需要求助于原始列表而不是创建一个新列表(由于列表的存储方式)。
- 源列表必须是
IList
(我不能使用List<T>
)
这是测试:
public class TestObject
{
public int Id { get; set; }
}
[Test]
public void Can_reorder_using_index_list()
{
IList<TestObject> list = new List<TestObject>
{
new TestObject { Id = 1 },
new TestObject { Id = 2 },
new TestObject { Id = 3 },
new TestObject { Id = 4 },
new TestObject { Id = 5 }
};
IList<int> indexList = new[] { 10, 5, 1, 9, 2 };
// TODO sort
Assert.That(list[0].Id, Is.EqualTo(5));
Assert.That(list[1].Id, Is.EqualTo(1));
Assert.That(list[2].Id, Is.EqualTo(2));
Assert.That(list[3].Id, Is.EqualTo(3));
Assert.That(list[4].Id, Is.EqualTo(4));
}
更新:
按照要求,这是我尝试过的,但是 1) 它只适用于 List<T>
和 2) 我不确定这是最有效的方法:
var clone = list.ToList();
list.Sort((x, y) =>
{
var xIndex = indexList.IndexOf(x.Id);
var yIndex = indexList.IndexOf(y.Id);
if (xIndex == -1)
{
xIndex = list.Count + clone.IndexOf(x);
}
if (yIndex == -1)
{
yIndex = list.Count + clone.IndexOf(y);
}
return xIndex.CompareTo(yIndex);
});
更新 2:
感谢@leppie、@jamiec、@mitch wheat - 这是工作代码:
public class TestObjectComparer : Comparer<TestObject>
{
private readonly IList<int> indexList;
private readonly Func<TestObject, int> currentIndexFunc;
private readonly int listCount;
public TestObjectComparer(IList<int> indexList, Func<TestObject, int> currentIndexFunc, int listCount)
{
this.indexList = indexList;
this.currentIndexFunc = currentIndexFunc;
this.listCount = listCount;
}
public override int Compare(TestObject x, TestObject y)
{
var xIndex = indexList.IndexOf(x.Id);
var yIndex = indexList.IndexOf(y.Id);
if (xIndex == -1)
{
xIndex = listCount + currentIndexFunc(x);
}
if (yIndex == -1)
{
yIndex = listCount + currentIndexFunc(y);
}
return xIndex.CompareTo(yIndex);
}
}
[Test]
public void Can_reorder_using_index_list()
{
IList<TestObject> list = new List<TestObject>
{
new TestObject { Id = 1 },
new TestObject { Id = 2 },
new TestObject { Id = 3 },
new TestObject { Id = 4 },
new TestObject { Id = 5 }
};
IList<int> indexList = new[] { 10, 5, 1, 9, 2, 4 };
ArrayList.Adapter((IList)list).Sort(new TestObjectComparer(indexList, x => list.IndexOf(x), list.Count));
Assert.That(list[0].Id, Is.EqualTo(5));
Assert.That(list[1].Id, Is.EqualTo(1));
Assert.That(list[2].Id, Is.EqualTo(2));
Assert.That(list[3].Id, Is.EqualTo(3));
Assert.That(list[4].Id, Is.EqualTo(4));
}
最佳答案
看了一会儿,确实如前所述,您将需要 ArrayList.Adapter ,但是您会注意到它采用非通用 IList,因此需要进行一些转换:
ArrayList.Adapter((IList)list)
您还需要编写一个比较器,其中包含进行排序的逻辑。请原谅这个名字但是:
public class WeirdComparer : IComparer,IComparer<TestObject>
{
private IList<int> order;
public WeirdComparer(IList<int> order)
{
this.order = order;
}
public int Compare(object x, object y)
{
return Compare((TestObject) x, (TestObject) y);
}
public int Compare(TestObject x, TestObject y)
{
if(order.Contains(x.Id))
{
if(order.Contains(y.Id))
{
return order.IndexOf(x.Id).CompareTo(order.IndexOf(y.Id));
}
return -1;
}
else
{
if (order.Contains(y.Id))
{
return 1;
}
return x.Id.CompareTo(y.Id);
}
}
}
编辑:为上面的比较器添加了实现
那么用法如下:
IList<int> indexList = new[] { 10, 5, 1, 9, 2 };
ArrayList.Adapter((IList)list).Sort(new WeirdComparer(indexList));
顺便说一下,this thread解释了一种将其转变为扩展方法的好方法,这将使您的代码更可重用且更易于阅读 IMO。
关于c# - 在不复制源列表的情况下高效地对 IList<T> 进行排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6660650/