我需要一个通用容器来保持其元素的排序,并且可以询问它将插入新元素的位置(在哪个位置),而不实际插入它。
.NET库中是否存在这样的容器? 最好的例子是一个例子(容器按ASCII值对字符进行排序,假设unicode不存在):
sortedContainer.Add('d');
sortedContainer.Add('b');
sortedContainer.Add('g');
//container contains elements ordered like 'b' 'd' 'g'
//index --------------------------------> 0 1 2
sortedContainer.GetSortedIndex('a'); //returns 0
sortedContainer.GetSortedIndex('b'); //returns 0
sortedContainer.GetSortedIndex('c'); //returns 1
sortedContainer.GetSortedIndex('d'); //returns 1
sortedContainer.GetSortedIndex('e'); //returns 2
sortedContainer.GetSortedIndex('f'); //returns 2
sortedContainer.GetSortedIndex('g'); //returns 2
sortedContainer.GetSortedIndex('h'); //returns 3
[...]
搜索位置应该利用元素排序的事实。
答案 0 :(得分:6)
如果您对List<T>
进行排序,然后使用List<T>.BinarySearch
,它将为您提供条目的索引(如果存在),或者 的索引的按位补码>插入后插入然后排序。从那以后,您应该能够轻松地构建您的方法。
示例代码与您的示例匹配,但不符合结果 - 如果您查看示例,则只有3个条目,因此“h”返回4或“g”返回3没有意义我希望这是你的例子稍微偏离,而不是我误解了问题:)注意排序不是自动的 - 你必须在调用GetSortedIndex之前显式排序列表。
using System;
using System.Collections.Generic;
static class Test
{
static int GetSortedIndex<T>(this List<T> list, T entry)
{
int index = list.BinarySearch(entry);
return index >= 0 ? index : ~index;
}
static void Main()
{
List<char> container = new List<char> { 'b', 'd', 'g' };
Console.WriteLine(container.GetSortedIndex('a'));
Console.WriteLine(container.GetSortedIndex('b'));
Console.WriteLine(container.GetSortedIndex('c'));
Console.WriteLine(container.GetSortedIndex('d'));
Console.WriteLine(container.GetSortedIndex('e'));
Console.WriteLine(container.GetSortedIndex('f'));
Console.WriteLine(container.GetSortedIndex('g'));
Console.WriteLine(container.GetSortedIndex('h'));
}
}
答案 1 :(得分:1)
最接近你要找的是SortedList<TKey,TValue>。此类将维护排序列表顺序。
但是,没有方法可以为新值添加索引。但是,您可以编写一个扩展方法,为您提供新索引
public int GetSortedIndex<TKey,TValue>(this SortedList<TKey,TValue> list, TKey key) {
var comp = list.Comparer;
for ( var i = 0; i < list.Count; i++ ) {
if ( comp.Compare(key, list.GetKey(i)) < 0 ) {
return i;
}
}
return list.Count;
}
答案 2 :(得分:0)
听起来像一个有趣的测试,所以我试了一下。可能不是最优雅,也不是最有效,但这应该有效:
public class SortedContainer<T> : IList<T> where T : IComparable<T>
{
private List<T> internalList = new List<T>();
public int IndexOf(T item)
{
return internalList.IndexOf(item);
}
public void Insert(int index, T item)
{
internalList.Insert(index, item);
}
public void RemoveAt(int index)
{
internalList.RemoveAt(index);
}
public T this[int index]
{
get
{
return internalList[index];
}
set
{
internalList[index] = value;
}
}
public void Add(T item)
{
internalList.Add(item);
this.Sort();
}
public void Clear()
{
internalList.Clear();
}
public bool Contains(T item)
{
return internalList.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
internalList.CopyTo(array, arrayIndex);
}
public int Count
{
get { return internalList.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(T item)
{
bool result = internalList.Remove(item);
this.Sort();
return result;
}
public IEnumerator<T> GetEnumerator()
{
return internalList.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return internalList.GetEnumerator();
}
private void Sort()
{
internalList.Sort();
}
private List<T> GetCopy()
{
return internalList.ToList();
}
public int GetSortedIndex(T item)
{
List<T> copy = GetCopy();
copy.Add(item);
copy.Sort();
return copy.IndexOf(item);
}
}
基本上,实现IList,并保留一个internatl List。每次调用Add方法时,都会在内部列表上调用sort。然后,当您想要获取已排序的索引而不实际添加时,它会创建该列表的副本,将该项插入到副本中,然后对该副本进行排序。然后它返回该项目的索引。此时的内部列表尚未受到影响。我测试了它并且它有效。
同样,可能效率不高。