在循环字典项目时“偷看前方”

时间:2009-11-03 18:53:55

标签: .net vb.net dictionary

这似乎应该是非常容易做到的事情,但每次我处理这个问题时,我最终都会感到“不够优雅”的解决方案

这是我的基本问题:如果我循环浏览我以特定方式排序的字典,在循环中的任何给定点内如何“窥视”或引用前面的字典项“x”在不更改当前枚举数的情况下当前项目?例如:

Dim tempDictionary = New Dictionary(Of String, String)

tempDictionary.Add("TestName1", "TestValue1")
tempDictionary.Add("TestName2", "TestValue2")
tempDictionary.Add("TestName3", "TestValue3")
'... and so on ...  '

For Each Item In tempDictionary
 DoStuff(Item)

 'Here is the point in which I want to see what the value of the'
 'dictionary item that is 1, 2, 3, [x] places in front of the current'
 'item without interfering w/ the current loop.'

 'CODE'

Next

提前致谢!

7 个答案:

答案 0 :(得分:4)

问题是Dictionary不是有序数据结构。您不能依赖于在“词典”中枚举项目的顺序。如果你需要按顺序排列项目,你应该坚持使用通用List,或使用第三方有序词典(例如Wintellect's Power Collections有一个)。

实际上,System.Collections.Specialized中有OrderedDictionary,但它不是通用的。

如果您想创建自己的通用有序词典,this CodeProject article可能会让您感兴趣。

答案 1 :(得分:1)

声音就像你想要一个c风格的循环。在这里原谅C#(因为你在VB中问过)

for (int i = 0; i < myArray.Length; i++) {
   object current = myArray[i];

   if(i + 1 < myArray.Length) { // make sure there is a next item
       object nextItem = myArray[i + 1]
   }
}

如上所述,字典不是有序的,但您可以将Keys放在一个数组中以使用上面的内容。

答案 2 :(得分:1)

这是一种向前看的方式。至于订单,我不会重复别人已经提到的内容。

Dim peek As Integer = 2   ''// peek ahead amount
For i As Integer = 0 To tempDictionary.Count - 1
    Dim key = tempDictionary.Keys(i)
    Dim value = tempDictionary.Values(i)
    Console.WriteLine("{0} : {1}", key, value)

    Dim peekIndex As Integer = i + peek
    If peekIndex < tempDictionary.Count - 1 Then
        Dim nextKey = tempDictionary.Keys(peekIndex)
        Dim nextValue = tempDictionary.Values(peekIndex)
        Console.WriteLine("Peek: {0} : {1}", nextKey, nextValue)
    End If
Next

答案 3 :(得分:0)

你问的是没有意义的,因为返回项目的顺序是不确定的。 dictionary中没有订单。

答案 4 :(得分:0)

我能想到的唯一方法是创建当前枚举器的副本并推进它(显然非常难看),或使用Linq的.skip()方法创建一个可以提前工作的枚举使用某种组合方法将两者结合起来,您将再次自己定义。

在另一点上:为了获得有意义的元素顺序,您可能希望使用System.Generics.SortedDictionary而不是标准元素。

这种方法适用于在给定适当的组合方法的情况下组合两个数据

    public static IEnumerable<TResult> Combine<TParam1, TParam2, TResult>(this IEnumerable<TParam1> self, IEnumerable<TParam2> other, 
                                                                              Func<TParam1, TParam2, TResult> combiner)
    {
        using(var first=self.GetEnumerator())
        using (var second = other.GetEnumerator())
        {
            while (first.MoveNext() && second.MoveNext())
                yield return combiner(first.Current, second.Current);
        }

    }

我无法保证这将完全像这样工作,因为我不得不从原始代码段中删除一些代码

编辑:在考虑了一下之后,这可能就是你想要的:(因为我的vb并不是那么棒,所以在c#中不幸):

skippedEnumerable = myEnumerable;         
myEnumerable.Select(item => {skippedEnumerable = skippedEnumerable.Skip(1); return new KeyValuePair<T, IEnumerable<T>>(item, skippedEnumerable )});

这将为您提供一对当前项和从当前位置开始的可枚举,因此您可以使用.ElementAt()轻松地偏移到该可枚举项。这可能会使可枚举内容非常深,因此可能(或者可能不是由于O(n ^ 2)运行时)更好地直接使用myEnumerable.Skipe(index);

答案 5 :(得分:0)

我不知道你想要对字典条目做些什么,但是这样的东西应该有效:

Dim dict As New Dictionary(Of String, String)
For i As Integer = 0 To dict.Count - 2
  If dict.ElementAt(i).Equals(dict.ElementAt(i + 1)) Then Exit For
Next

ElementAt()是Linq函数。但是,如果你像这样迭代列表,我想知道字典是否适合使用。通用列表可能更好。

答案 6 :(得分:0)

最有可能的是,你想要按照你想要的顺序用字典中的键创建一个数组,并使用索引迭代它。

也就是说,你的for循环将是for的vb等价物(int i = 0; i&lt; array.length; i ++), 你会用字典[array [i]]查找字典值。当然,你可以用i代替i + 1(带边界检查)。