C# 展开字典或哈希表以包含弹出和推送 (LIFO)
本文关键字:LIFO 包含弹 字典 哈希表 | 更新日期: 2023-09-27 18:35:06
查找包含堆栈优点但仅包含一个与键匹配的项目的结构。
例如数据来自各种客户端,我只对来自特定客户端的最后一条数据感兴趣。所以字典会很好用。但是,我想在 LIFO 场景中处理来自所有客户端的数据,因此堆栈是最好的。
关于将两者结合起来的任何想法?
有几种方法可以解释你想要的东西。 例如,当您Push
一个带有已经存在的键的值时,会发生什么?
- 弹出现有项目,推送新项目,
- 将现有项的值替换为新数据
- 例外
如果LIFO方面是关键考虑因素,则主要需要修改Stack
才能将密钥与数据相关联。LinkedList
将是另一种选择。
Push
/Pop
List
将需要将其Insert(0)
实施并RemoveAt(0)
。 这意味着将为每个操作重新构建基础数组。 Stack
的工作方式正好相反:新项目存储在数组的末尾,因此只需定期重建即可。
根据数据的大小和数量,这可能无关紧要。
在提到Dictionary
时,不清楚您是否还需要通过密钥访问;也就是说,您可以Pop
项目,也可以通过密钥检索它们。 这似乎与Stack
的性质不一致。 首先,一个将键(名称)与项相关联的类:
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
将重复项视为新项目(它们会丢失旧位置):
' 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
似乎你想要一些叫做HashStack<T>
的东西。
T
需要实现IEquatable<T>
或覆盖Equals
和GetHashCode
,或者您可以接受IEqualityComparer<T>
。
如果你不想让事情过于复杂,你需要用Push
方法实现IList<T>
。Add
方法将由 Push
调用,它需要通过调用项目的 GetHashCode
/Equals
来评估要添加的项目是否已经在堆栈中,或者您还可以维护一个内部HashSet<T>
来优化已经实现相等性检查的检查(如果项目已经在集合中,HashSet<T>.Add
将返回false
......
项目还需要存储在内部List<T>
中,以便能够按广告顺序获取最后一项。