如何从SortedDictionary获取以前的密钥?

时间:2011-01-18 05:09:45

标签: c# .net linq sorteddictionary

我有包含键值对的字典。

SortedDictionary<int,int> dictionary=new SortedDictionary<int,int>();
dictionary.Add(1,33);
dictionary.Add(2,20);
dictionary.Add(4,35);

我想从已知的键值获取以前的键值对。在上面的例子中,如果我有密钥4,那么我该如何获得<2,20>

7 个答案:

答案 0 :(得分:10)

使用SortedDictionary<TKey, TValue>很难有效地实现这一点,因为它是作为二进制搜索树实现的,不会公开前任或后继者。

您当然可以枚举每个KeyValuePair,直到找到&#34;已知&#34;键。使用一点LINQ,这看起来像(假设密钥肯定存在并且不是第一个密钥):

SortedDictionary<int, int> dictionary = ...
int knownKey = ...

var previousKvp = dictionary.TakeWhile(kvp => kvp.Key != knownKey)
                            .Last();

如果这些假设不成立,你可以这样做:

var maybePreviousKvp = dictionary.TakeWhile(kvp => kvp.Key != knownKey)
                                 .Cast<KeyValuePair<int, int>?>()
                                 .LastOrDefault();

(检查maybePreviousKvp != null以确定先前的KeyValuePair已成功检索。)

但这根本不是高效的。


如果可行,请考虑使用SortedList<TKey, TValue>代替(显然,如果您不能采用较慢的插入和删除,则可能无法实现)。此集合支持 ordered 索引的高效密钥和值检索,因为它是作为可扩展的数组实现的。然后您的查询变得如此简单:

SortedList<int, int> dictionary = ...
int knownKey = ...

int indexOfPrevious = dictionary.IndexOfKey(knownKey) - 1;

// if "known" key exists and isn't the first key
if(indexOfPrevious >= 0)
{
   // Wrap these in a KeyValuePair if necessary
   int previousKey = dictionary.Keys[indexOfPrevious];
   int previousValue = dictionary.Values[indexOfPrevious];      
}

IndexOfKey在密钥列表上运行二进制搜索,在O(log n)时间内运行。其他一切都应该在恒定的时间内运行,这意味着整个操作应该以对数时间运行。


否则,您必须实现自己/找到确实暴露前任/后继者的BST集合。

答案 1 :(得分:5)

我也在寻找这个问题的答案,我认为比这里的所有答案更好的解决方案是使用TreeDictionary<K, V> C5 Collections / {GitHub {{}} {3}}),这是一个红黑树的实现。

它有Predecessor / TryPredecessorWeakPredessor / TryWeakPredecessor方法(以及后续版本的等效方法),可以完全按照您的要求进行操作。

例如:

TreeDictionary<int,int> dictionary = new TreeDictionary<int,int>();
dictionary.Add(1,33);
dictionary.Add(2,20);
dictionary.Add(4,35);

// applied to the dictionary itself, returns KeyValuePair<int,int>
var previousValue = dictionary.Predecessor(4);
Assert.Equals(previousValue.Key, 2);
Assert.Equals(previousValue.Value, 20);

// applied to the keys of the dictionary, returns key only
var previousKey = dictionary.Keys.Predecessor(4);
Assert.Equals(previousKey, 2);

// it is also possible to specify keys not in the dictionary
previousKey = dictionary.Keys.Predecessor(3);
Assert.Equals(previousKey, 2);

答案 2 :(得分:4)

KeyValuePair<int, int> lookingForThis = dictionary
  .Reverse()
  .SkipWhile(kvp => kvp.Key != 4)
  .Skip(1)
  .FirstOrDefault();

答案 3 :(得分:1)

Dictionary<TKey,TValue>未分类,因此某些项目没有上一个项。相反,您可以使用SortedDictionary<TKey,TValue>

编辑:对不起,我只读了标题LOL。

如果您必须使用LINQ:

int givenKey = 4;
var previousItem = dict.Where((pair, index) => 
                                   index == dict.Count || 
                                   dict.ElementAt(index + 1).Key == givenKey)
                       .FirstOrDefault();

答案 4 :(得分:1)

我猜你可以遍历字典并跟踪值。像这样:

public int GetPreviousKey(int currentKey, SortedDictionary<int, int> dictionary)
{
    int previousKey = int.MinValue;
    foreach(KeyValuePair<int,int> pair in dictionary)
    {
        if(pair.Key == currentKey)
        {
            if(previousKey == int.MinValue)
            {
                throw new InvalidOperationException("There is no previous key.");
            }
            return previousKey;
        }
        else
        {
            previousKey = pair.Key;
        }
    }
}

但是,这是一个非常奇怪的操作要求。您需要它的事实可能是指出您的设计存在问题。

答案 5 :(得分:1)

我更愿意使用linq,如果是这样的话......试试这肯定会有效

SortedDictionary<int,int> dictionary = new SortedDictionary<int,int>();
dictionary.add(1, 33);
dictionary.add(2, 20);
dictionary.add(4, 35);

int SelectedKey = 4;

var ResutValue = ( from n in dictionary    
               where n.Key < TheSelectedKey
               select n.Value).Last();

this.txtResult.Text = ResultValue.ToString();

答案 6 :(得分:0)

这个怎么样?我没有测试过,但是应该从这个方向开始思考。希望它有所帮助。

        int input = 4;
        List<int> lKeys = dictionary.Keys.ToList();
        int reqIndex = lKeys.IndexOf(input) - 1;
        int reqAnswer = dictionary[reqIndex];

测试其他条件,如if(reqIndex!= -1)等。