获取下一个KeyValuePair<,>来自字典<,>没有索引

时间:2016-09-09 11:59:06

标签: c# dictionary

是否可以在KeyValuePair<,>或下一个对象中获取给定Dictionary<,>的位置,而不是index或类似?

例如,假设我有以下代码:

Dictionary<Object, String>
    dictionary = new Dictionary<Object, String>() {
        { new Object(), "String A" },
        { new Object(), "String B" },
        { new Object(), "String C" },
        { new Object(), "String D" },
        { new Object(), "String E" },
        { new Object(), "String F" },
    };

String
    knownValue = "String C";

从那里开始,我应该如何获得KeyValuePair<Object, String>索引或KeyValuePair<Object, String> "String D"值?

更新

更多信息

在给定的示例和我尝试执行此操作的位置,KeysValues都是唯一的。我使用Dictionary<,>跟踪两个对象,同时知道哪个对象与之关联。

稍微详细一点,我使用此Dictionary<,>来跟踪Android应用中的位置和Marker。我被要求在选择Marker并弹出一张并提供有关该位置的基本信息后,启用该并显示下一个或上一个位置。

这是此问题进入的地方。我从服务器收到一个位置列表,必须保留该订单。处理完该列表后,我将每个位置与地图上的Marker相关联。

此时,每当用户点击Marker时,我都会使用LINQ表达式在Marker上找到Dictionary<,>并检索相关位置。

7 个答案:

答案 0 :(得分:4)

A Dictionary(TKey,TValue),不会以列表格式存储数据,它(非常非常简单地)散列密钥并将其存储在存储桶中,因此它没有&#34; next&#34;的概念。也许你可以考虑使用SortedDictionary(TKey, TValue)。然后,您可以使用迭代器以您需要的顺序遍历元素。

答案 1 :(得分:4)

字典中的顺序是非确定性的

请参阅:The order of elements in Dictionary

你可以使用OrderedDictionary虽然(https://msdn.microsoft.com/en-us/library/system.collections.specialized.ordereddictionary(v=vs.110).aspx

答案 2 :(得分:2)

在C#中,Dictionary没有索引这样的东西 - 对象没有按特定顺序保存。这是因为字典的工作原理,它们根据键的哈希将键和值放在所谓的“桶”中。

如果您需要对要素进行排序,则可以改为使用SortedDictionary

也许你只需要枚举所有元素,在这种情况下你应该这样做:

foreach (var kvp in dictionary)
{
    if ("String D".Equals(kvp.Value))
    ; //do stuff
}

如果您需要能够按键以及按值搜索,则可能更适合使用不同的结构。例如,请参阅here

问题编辑后:

编辑让它变得有趣,这应该适合你:

class SortedBiDcit<T1, T2> //this assumes T1 and T2 are different (and not int for indexer) and values are unique
{
    Dictionary<T1, Tuple<T2, int>> dict1 = new Dictionary<T1, Tuple<T2, int>>();
    Dictionary<T2, T1> dict2 = new Dictionary<T2, T1>();

    List<T1> indices = new List<T1>();

    public int Count { get { return indices.Count; } }

    public T2 this[T1 arg]
    {
        get { return dict1[arg].Item1; }
    }

    public T1 this[T2 arg]
    {
        get { return dict2[arg]; }
    }

    public Tuple<T1, T2> this[int index]
    {
        get
        {
            T1 arg1 = indices[index];
            return new Tuple<T1, T2>(arg1, dict1[arg1].Item1);
        }
    }

    public void Add(T1 arg1, T2 arg2)
    {
        dict1[arg1] = new Tuple<T2, int>(arg2, indices.Count);
        dict2[arg2] = arg1;

        indices.Add(arg1);
    }

    public void Remove(T1 arg)
    {
        var arg2 = dict1[arg];
        dict1.Remove(arg);
        dict2.Remove(arg2.Item1);
        indices.RemoveAt(arg2.Item2);
    }

    public void Remove(T2 arg)
    {
        var arg2 = dict2[arg];
        var arg1 = dict1[arg2];

        dict1.Remove(arg2);
        dict2.Remove(arg1.Item1);
        indices.RemoveAt(arg1.Item2);
    }
}

它缺少基本的错误检查,但您可以从那里获取它。它应该允许你像这样使用它:

var test = new SortedBiDcit<object, string>();
test.Add(new object(), "test");
for (int i = 0; i < test.Count; ++i)
{
    var tuple = test[i];
    var str = test[tuple.Item1]; //retrieve T2
    var obj = test[tuple.Item2]; //retrieve T1
    Console.WriteLine(tuple.Item2); //prints "test"
}

希望它有所帮助!

答案 3 :(得分:0)

我认为你应该使用KeyedCollection<TKey,TItem>,它专为此而设计...... you can do myKeyedCollectionObject[TItem] ---> return TKEY

演示

.NET Fiddle Sample

在示例中,我使用索引或值作为索引。

.NET Reference for souce code

更新

KeyedCollection<TKey,TItem>有一个TItems列表(List<TItems>)和一个Dictionary<TKey,TItem> 两者都在幕后保持同步。

使用它的主要论点是当你想从值中提取键时,因为这就是你想要的......我认为这应该适合你!

答案 4 :(得分:0)

嗯,从技术上讲,这是一种在字典中查找值的索引的方法。

dictionary.Values字段是Dictionary<T1,T2>.ValueCollection,其继承自IEnumerable<T2>

作为IEnumerable,您可以使用foreach进行迭代,或使用类似的内容

IEnumerable<Int32> idxs = dictionary.values.SelectMany(
    (string value, Int32 idx) => 
    (value == "insertStringHere") ? (new int[]{ idx }) : {new int[]{}}
);

选择您要查找的值的索引(或所有索引,如果有重复)。

我不会推荐它,与其他答案的推理相同,因为Dictionary不保证值的顺序。它可能适用于SortedDictionarySortedList

(编辑:或KeyedCollection明显,https://stackoverflow.com/users/1892381/olivier-albertini指出)

答案 5 :(得分:-1)

由于SortedDictionarykey排序,而不是add()排序, 我相信SortedDictionary 你想要的是什么。

也许OrderedDictionary是你想要的,但看起来你是WP的开发人员,OrderedDictionary是WP的版本。

您的knownValue是一个值(不是键),所以我认为最好的方法是:

var list = new List<string>() { .... , "String C", "String D", ... };
// if you still need dict, then:
var dictionary = list.ToDictionary(z => new object());
// whatever, find the "String D"
var knownValue = "String C";
var ret = list.SkipWhile(z => z != knownValue).Skip(1).First();

更新后

为什么不创建一个类?

class A
{
    Marker;
    Location;
}

当用户点击它时,你应该得到A,而不是标记。

答案 6 :(得分:-2)

这个问题实际上有一个相当简单的解决方案 - 尽管不是很好,但它可以完成这项工作。

在这种情况下,我试图从Dictionary对象获取下一个或上一个条目。不幸的是,它没有类似IndexOf( ... )的{​​{1}},所以我无法执行List之类的操作。

但是Dictionary[index + 1]个对象可以索引它们。转换为Dictionary后,通过Dictionary.KeysDictionary.Values。它不是我们习惯的索引,但它已接近。

考虑到这一点,我可以像这样创建一个扩展名:

List

这些扩展适合我的需要。

有了这个,我可以获得任何给定public static KeyValuePair<K, V> After<K, V>( this Dictionary<K, V> dictionary, K key ) { Int32 position = dictionary.Keys.ToList().IndexOf( key ); if( position == -1 ) throw new ArgumentException( "No match.", "key" ); position++; if( position >= dictionary.Count ) position = 0; K k = dictionary.Keys.ToList()[ position ]; V v = dictionary.Values.ToList()[ position ]; return new KeyValuePair<K, V>( k, v ); } public static KeyValuePair<K, V> After<K, V>( this Dictionary<K, V> dictionary, V value ) { Int32 position = dictionary.Values.ToList().IndexOf( value ); if( position == -1 ) throw new ArgumentException( "No match.", "value" ); position++; if( position >= dictionary.Count ) position = 0; K k = dictionary.Keys.ToList()[ position ]; V v = dictionary.Values.ToList()[ position ]; return new KeyValuePair<K, V>( k, v ); } public static KeyValuePair<K, V> Before<K, V>( this Dictionary<K, V> dictionary, K key ) { Int32 position = dictionary.Keys.ToList().IndexOf( key ); if( position == -1 ) throw new ArgumentException( "No match.", "key" ); position--; if( position < 0 ) position = dictionary.Count - 1; K k = dictionary.Keys.ToList()[ position ]; V v = dictionary.Values.ToList()[ position ]; return new KeyValuePair<K, V>( k, v ); } public static KeyValuePair<K, V> Before<K, V>( this Dictionary<K, V> dictionary, V value ) { Int32 position = dictionary.Values.ToList().IndexOf( value ); if( position == -1 ) throw new ArgumentException( "No match.", "value" ); position--; if( position < 0 ) position = dictionary.Count - 1; K k = dictionary.Keys.ToList()[ position ]; V v = dictionary.Values.ToList()[ position ]; return new KeyValuePair<K, V>( k, v ); } After的条目Before / Key

您可以查看它有效here