寻找包含堆栈优点的结构,但只能包含一个与密钥匹配的项目。
例如 数据来自不同的客户端,我只对来自特定客户端的最后一段数据感兴趣。所以字典可以很好地工作。但是我想在LIFO场景中处理来自所有客户端的数据,因此堆栈最好。
关于两者结合的任何想法?
答案 0 :(得分:1)
您似乎想要一些名为HashStack<T>
的东西。
T
需要实施IEquatable<T>
或覆盖Equals
和GetHashCode
,否则您可以接受IEqualityComparer<T>
。
如果您不想让事情过于复杂,那么您需要使用IList<T>
方法实施Push
。 Add
方法将由Push
调用,并且需要通过调用项目GetHashCode
/来评估要添加的项目是否已经在堆栈中Equals
或者你也可以维护一个内部HashSet<T>
来优化已经实现了相等性检查的检查(如果项目已经在集合中,HashSet<T>.Add
将返回false
。 )。
项目也需要存储在内部List<T>
中,才能按插入顺序获取最后一项。
答案 1 :(得分:1)
有几种方法可以解释你想要的东西。例如,当你Push
一个已经存在密钥的值时,会发生什么?
如果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