Skippy
Skippy

Reputation: 19

Is there a smart way to duplicate a Stack(Of ...)

In vb.net, I'm trying to create an extension to duplicate/reverse/merge stacks. Please note that it might exists already but I'm facing an issue.

I've a module, called utility.vb that hold a whole bunch of <Extension()> like the Duplicate that I'm trying to write.

''' <summary>
''' Duplicate a stack of object to another
''' </summary>
''' <typeparam name="T">Object type in the stack</typeparam>
''' <param name="s">Stack to duplicate</param>
''' <returns></returns>
<Extension()>
Public Function Duplicate(Of T)(ByVal s As Stack(Of T())) As Stack(Of T())
    Dim tmp As New Stack(Of T())
    For i As Integer = s.Count - 1 To 0 Step -1
        tmp.Push(s(i))
    Next
    Return tmp
End Function

I'm doing a various amount of Push in a Stack called labelStack. But when I call the Duplicate function from my code (because I need to re-use the same stack multiple times), it is not compiling (please note that the stack is made of own created object class)

Dim summaryStack As Stack(Of CCNode) = labelStack.Duplicate()

The error is "'Duplicate' is not a member of 'Stack(Of MyForm.CCNode)'"

I also tried to change the signature of the extension like so:

Public Function Duplicate(Of T As {New})(ByVal s As Stack(Of T())) As Stack(Of T())

But without any success.

Can someone help me (pointing out my mistake, correcting it or give me a way to achieve my need without writing the function myself)?

P.S.: I'm using Stack because I need to Pop in reverse order of my Push and it seemed appropriate.

Upvotes: 0

Views: 121

Answers (1)

jmcilhinney
jmcilhinney

Reputation: 54457

You're doing it all wrong. If you want to reuse or reverse or any such thing then you should not be creating a Stack(Of T) to start with. Create either an array or a List(Of T), depending on whether you want be able to adjust the content, and then you can create as many Stack(Of T) and Queue(Of T) objects as you want from that. Both of those classes have a constructor that accepts an IEnumerable(Of T) as an argument so you can pass your array or List(Of T) to as many of those constructors as you like, e.g.

Dim items = {1, 2, 3, 4}
Dim s1 As New Stack(Of Integer)(items)
Dim s2 As New Stack(Of Integer)(items.Reverse())
Dim q1 As New Queue(Of Integer)(items)
Dim q2 As New Queue(Of Integer)(items.Reverse())

That said, I just did this:

Imports System.Runtime.CompilerServices

Public Module StackExtensions

    <Extension>
    Public Function Copy(Of T)(source As Stack(Of T)) As Stack(Of T)
        Dim newStack As New Stack(Of T)

        For Each item In source.Reverse()
            newStack.Push(item)
        Next

        Return newStack
    End Function

End Module

and it worked exactly as you want. I expected the input stack to be empty after that, as I thought that enumerating a Stack(Of T) would pop each item but, apparently, it doesn't.

Actually, I just realised that that means that the Stack(Of T) constructor will accept another Stack(Of T) as an argument, which makes the extension method even simpler:

Imports System.Runtime.CompilerServices

Public Module StackExtensions

    <Extension>
    Public Function Copy(Of T)(source As Stack(Of T)) As Stack(Of T)
        Return New Stack(Of T)(source.Reverse())
    End Function

End Module

That's so simple that I don't think that an extension method is even worth bothering with.

All that said, I'd still go with the array or List(Of T) as a single source of truth and create all the stacks from that. That way you can't possibly pop an item before you've created all the copies you need.

Upvotes: 1

Related Questions