C#Expand Dictionary或Hashtable包含Pop和Push(LIFO)

时间:2016-02-18 07:05:23

标签: c# .net vb.net dictionary stack

寻找包含堆栈优点的结构,但只能包含一个与密钥匹配的项目。

例如 数据来自不同的客户端,我只对来自特定客户端的最后一段数据感兴趣。所以字典可以很好地工作。但是我想在LIFO场景中处理来自所有客户端的数据,因此堆栈最好。

关于两者结合的任何想法?

2 个答案:

答案 0 :(得分:1)

您似乎想要一些名为HashStack<T>的东西。

T需要实施IEquatable<T>或覆盖EqualsGetHashCode,否则您可以接受IEqualityComparer<T>

如果您不想让事情过于复杂,那么您需要使用IList<T>方法实施PushAdd方法将由Push调用,并且需要通过调用项目GetHashCode /来评估要添加的项目是否已经在堆栈中Equals或者你也可以维护一个内部HashSet<T>来优化已经实现了相等性检查的检查(如果项目已经在集合中,HashSet<T>.Add将返回false。 )。

项目也需要存储在内部List<T>中,才能按插入顺序获取最后一项

答案 1 :(得分:1)

有几种方法可以解释你想要的东西。例如,当你Push一个已经存在密钥的值时,会发生什么?

  1. 弹出现有项目,推送新项目
  2. 用新数据替换现有项目的值
  3. 异常
  4. 如果LIFO方面是关键考虑因素,则主要需要修改Stack来将密钥与数据相关联。 LinkedList是另一种选择。

    Push上的

    Pop / List需要将其作为Insert(0)RemoveAt(0)来实施。这意味着将为每个操作 重建基础数组。 Stack反向运作:新项目存储在数组的 end 中,因此只需定期重建。

    根据数据的大小和数量,这可能无关紧要。

    在提及Dictionary时,您是否也希望按密钥访问变得不清楚;也就是说,您可以Pop个项目,但也可以通过密钥检索它们。这似乎与Stack的性质不一致。首先,将Key(名称)与项目关联的类:

    Class NameValuePair(Of T)
        Public Property Name As String
        Public Property Value As T
    
        Public Sub New(n As String, v As T)
            Name = n
            Value = v
        End Sub
    
        Public Sub New(n As String)
            Name = n
        End Sub
    
        Public Overrides Function ToString() As String
            Return String.Format("{0} ({1})", Name, Value.ToString)
        End Function
    End Class
    

    然后是堆栈般的集合。这肯定需要工作,取决于上述和其他未知的答案。如果数据量很小,为了简单起见,我可能会坚持使用List

    Public Class KeyedStack(Of T)
        Private myStack As Stack(Of NameValuePair(Of T))
    
        Public Sub New()
            myStack = New Stack(Of NameValuePair(Of T))
        End Sub
    
        Public Sub Push(key As String, value As T)
            Dim item = myStack.FirstOrDefault(Function(k) String.Compare(k.Name, key, True) = 0)
            If item IsNot Nothing Then
                ' replace
                item.Value = value
            Else
                myStack.Push(New NameValuePair(Of T)(key, value))
            End If
        End Sub
    
        Public Function Pop() As T
            ' todo check count
            Dim item = myStack.Pop
            Return item.Value
        End Function
    
        Public Function Peek() As T
            Return myStack.Peek().Value
        End Function
    
        ' ToDo: add Count, Contains, ContainsKey as needed
    End Class
    

    密钥不区分大小写。基础Stack提供排序,而NameValuePair提供类字典密钥。

    如果您需要Push将dupes视为新物品(他们将旧地方放松):

    ' replace item as new
    Public Sub PushAsNew(key As String, value As T)
        Dim tmp = myStack.ToList()
        Dim ndx = tmp.FindIndex(Function(k) String.Compare(k.Name, key, True) = 0)
    
        If ndx > -1 Then
            tmp.RemoveAt(ndx)
            myStack = New Stack(Of NameValuePair(Of T))(tmp.ToArray.Reverse)
        End If
    
        myStack.Push(New NameValuePair(Of T)(key, value))
    End Sub
    

    由于Stack项不打算通过索引删除,因此这样做变得非常昂贵(堆栈列表到数组到反向数组到新堆栈)。 PopByKey方法同样昂贵。希望你不需要它。 Ulta简单测试:

    Dim data = {"Alpha", "Beta", "Gamma", "Delta", "Echo", "Ziggy"}
    Dim stacker = New KeyedStack(Of String)
    
    For Each s As String In data
        stacker.Push(s(0), s)
    Next
    ' result == Z, E, D, G, B, A order
    
    stacker.Push("a", "Apple")
    ' item(5) is now {A, Apple} (key case ignored)
    
    Dim item = stacker.Pop
    ' item == "Ziggy"
    
    item = stacker.PopKey("g")
    ' new contents ==  E, D, B, A 
    ' item == "Gamma"
    
    stacker.PushAsNew("B", "Bottle")
    ' new contents ==  B, E, D, A