关于c#:获取下一个KeyValuePair<,>

Get the next KeyValuePair<,> from a Dictionary<,> without index

在没有index或类似物的情况下,是否可以在Dictionary<,>或下一个物体内获得给定KeyValuePair<,>的位置?

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

1
2
3
4
5
6
7
8
9
10
11
12
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";

从那里,我应该如何继续获得具有"String D"值的KeyValuePair指数或KeyValuePair

更新更多信息

在给出的例子和我想做的地方,KeysValues都是独一无二的。我正在使用Dictionary<,>跟踪两个对象,同时知道哪个对象与之相关。

更详细的一点,我使用这个Dictionary<,>来跟踪一个位置和一个android应用程序上的Marker。我被要求在选择了一个Marker并弹出一张包含该位置基本信息的小卡片后,启用刷卡并显示下一个或上一个位置。

这就是这个问题的切入点。我从一个服务器收到一个位置列表,这个列表必须保存。处理完这个列表后,我将每个位置与地图上的Marker相关联。

此时,每当用户单击Marker时,我使用LINQ表达式查找Dictionary<,>上的Marker并检索相关位置。


字典中的顺序是不确定的。

参见:字典中元素的顺序

但是,您可以使用OrderedDictionary(https://msdn.microsoft.com/en-us/library/system.collections.specialized.orderedDictionary(v=vs.110).aspx)


Dictionary(TKey,TValue)不以列表格式存储它的数据,它(非常非常简单)散列密钥并将其存储在bucket中,因此它没有"下一步"的概念。也许你可以考虑使用SortedDictionary(tkey,tvalue)。然后,您可以使用迭代器按需要的任何顺序移动元素。


在c中,Dictionary没有索引对象这样的东西——对象没有特殊的顺序。这是因为字典是如何工作的,它们根据键的散列值将键和值放在所谓的"bucket"中。

如果需要对元素进行排序,可以使用SortedDictionary

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

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

如果您需要能够按关键字和值进行搜索,那么不同的结构可能更适合。例如,请参见此处

问题编辑后:

编辑让它变得有趣,这应该对你有用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
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);
    }
}

它缺乏基本的错误检查,但您可以从中获得它。它应该允许您这样使用它:

1
2
3
4
5
6
7
8
9
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"
}

希望有帮助!


从技术上讲,有一种方法可以在字典中找到值的索引。

dictionary.Values字段是从IEnumerable继承的Dictionary.ValueCollection字段。

作为一个IEnumerable,您可以使用foreach迭代它,或者使用类似的东西

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

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

不过,我不建议这样做,因为Dictionary并不保证价值顺序。不过,它可能对SortedDictionarySortedList起作用。

(编辑:或KeyedCollectionApparenty,如https://stackoverflow.com/users/1892381/olivier-albertini指出的那样)


我想你应该使用KeyedCollection,它是为这个设计的……埃多克斯1〔5〕

演示

.NET小提琴示例

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

源代码的.NET引用

更新

KeyedCollection有一系列效价(ListDictionary。两者在幕后保持同步。

使用这个的主要参数是当您想从值中提取键时,因为这是您想要的…我认为这对你很有用!


因为SortedDictionary是按key排序,不是按add()排序,我相信江户一〔3〕不是你想要的。

也许你想要的是OrderedDictionary,但看起来你是一个wp开发者,OrderedDictionary不是wp的发行版。

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

1
2
3
4
5
6
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();

更新后

为什么不创建一个类呢?

1
2
3
4
5
class A
{
    Marker;
    Location;
}

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


这个问题实际上有一个相当简单的解决方案——虽然不是很好,但它确实起到了作用。

在这种情况下,我试图从Dictionary对象获取下一个或上一个条目。不幸的是,它没有像List那样的IndexOf( ... ),所以我不能做像Dictionary[index + 1]那样的事情。

但是Dictionary对象有一种索引方法。通过Dictionary.Keysdictionary.Values转换成List后。这不是我们习惯的索引,而是它接近的。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
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 );
}

这个扩展适合我需要的。

有了这个,我就可以得到任何给定的keyValueAfterBefore条目。

你可以在这里查看。