Jump to content
dummzeuch

TStack<T>.Peek deeper than the topmost element

Recommended Posts

If I want to get the topmost element of a stack (System.Generics.Collections.TStack<T>), without removing it, I use TStack<T>.Peek.

 

Is there any way to get the second to topmost element?

 

I looked at the sources and found none, so the only way I could come up with is:

TopElement := MyStack.Pop;
SecondElement := MyStack.Peek; // <== I want this one
MyStack.Push(TopElement);
if SecondElement = SearchedForElement then begin
  // ...
end;

Alternatively I would settle for a way to check whether the stack contains a given element:

if MyStack.Contains(SearchedForElement) then begin
  // ...
end;

But there doesn't seem to be such a method either.

 

Is there maybe a different container for that?

Share this post


Link to post
3 minutes ago, Dmitry Arefiev said:

MyStack.List[MyStack.Count - 2]

TStack<T> does not have a List property (at least in Delphi 10.2)

Share this post


Link to post
20 minutes ago, David Heffernan said:

Seems like you want TList<T>

That's one option, yes, but then I would have to implement the stack functionality myself.

Share this post


Link to post
3 hours ago, dummzeuch said:

That's one option, yes, but then I would have to implement the stack functionality myself.

Well, what's stopping you doing that? It's not a challenge. If you want random access to the entire collection, a stack isn't for you. 

Share this post


Link to post
7 minutes ago, David Heffernan said:

Well, what's stopping you doing that? It's not a challenge. If you want random access to the entire collection, a stack isn't for you. 

I don't want random access to the complete stack, just to the second to topmost entry. And for that I have got a solution that works but is clunky. Since I have only recently begun to use the generics that come with the RTL (Yes, I'm late to the party), I was hoping I might have overlooked something like TStack<T>.Peek(_IndexFromTop: integer): T. Apparently there isn't.

Share this post


Link to post

Adding push pop and peek to TList is incredibly simple. I thought you wanted access to them all because you talked about searching the collection for a specific item. Do you not need to do that? 

Share this post


Link to post
23 minutes ago, David Heffernan said:

Adding push pop and peek to TList is incredibly simple.

Yeah. I've been there: "It's simple, I'll write my own". [writes his own, overlooks a corner case and then takes 5 hours to find that bloody bug]

 

23 minutes ago, David Heffernan said:

I thought you wanted access to them all because you talked about searching the collection for a specific item. Do you not need to do that? 

No. As I wrote:

5 hours ago, dummzeuch said:

Alternatively I would settle for a way to check whether the stack contains a given element:


if MyStack.Contains(SearchedForElement) then begin
  // ...
end;

But there doesn't seem to be such a method either.

(emphasis mine)

Edited by dummzeuch

Share this post


Link to post

using "System.Generics.Collections" or "System.Contnrs"?


 

uses
  // System.Contnrs;
  System.Generics.Collections;

var
  MyStackList: TStack<TButton>;
  // MyStackList: TStack;

procedure TForm1.Button1Click(Sender: TObject);
var
  i: integer;
begin
  // System.Generics.Collections.pas
  MyStackList := TStack<TButton>.Create;
  try
    // MyStackList.TEnumerator  ...
    //
    i := MyStackList.Count - 2; // before last
    if (i >= 0) then
      MyStackList.List[ ...i...] .Caption := 'hello world';
    //
    // MyStackList.Push( buttonX )
    // MyStackList.Pop;
    // MyStackList.Peek;
    // MyStackList.Count;

    // *************************//
    // System.Contnrs.pas;
    // MyStackList.AtLeast( n )
    // MyStackList.Push() // add
    // MyStackList.Pop; //remove e return
    // MyStackList.Peek; // next on list, no remove
    // MyStackList.Count // how many
  finally
    MyStackList.Free;
  end;
end;


 

Edited by programmerdelphi2k

Share this post


Link to post
39 minutes ago, dummzeuch said:

Yeah. I've been there: "It's simple, I'll write my own"

Push is Add. Pop is Extract(Count-1) and Peek is Items[Count-1]

 

Contains won't help you because it checks the entire collection, not just the top two.

Share this post


Link to post
type
  TMyStack<T> = class(TStack<T>)
    function Peek(indexFromTop: Integer): T; overload; inline;
  end;

{$IF RTLVersion < 33}
type
  TStackAccess<T> = class(TEnumerable<T>)
    FItems: TArray<T>;
    property List: TArray<T> read FItems;
  end;
{$IFEND}

function TMyStack<T>.Peek(indexFromTop: Integer): T;
begin
  Result := {$IF RTLVersion < 33}TStackAccess<T>(Self).{$IFEND}List[Count - indexFromTop - 1];
end;

 

Edited by Stefan Glienke
  • Like 1

Share this post


Link to post
1 hour ago, dummzeuch said:

So basically, the answer is "No".

You can look at the list of public methods and properties. Why do you need us to tell you that what you want isn't there? Didn't all the responses suggesting alternatives indicate that? 

Share this post


Link to post
21 hours ago, dummzeuch said:

Is there any way to get the second to topmost element?

Yes.

 

If you wanted to know if there is any method that does that then you should have expressed your question more precisely. But hey let's ask a vague question and then offend anyone providing help by ignoring them.

Edited by Stefan Glienke

Share this post


Link to post

Yeah, that's me.

 

Ok, the problem seems to be that I'm unable to ask the question so people understand it. Sorry for that, maybe I should stick with the German forum.

 

What I wanted to know is if there is an easier way to get to the second topmost item than the one I described in my original post.

 

The answer to that seems to be "No", as far as I understand it.

 

So I've put those 3 lines of code into a function and live with it.

Edited by dummzeuch

Share this post


Link to post
2 hours ago, dummzeuch said:

What I wanted to know is if there is an easier way to get to the second topmost item than the one I described in my original post.

The answer still is yes - your code actually mutated the stack - all proposed answers avoided that - some even avoided any allocation and mine even gave you a drop-in solution.

 

The only question that could be answered with "No" would have been: Is there any solution to this problem where I don't have to write any code for?

Edited by Stefan Glienke

Share this post


Link to post
2 hours ago, dummzeuch said:

So I've put those 3 lines of code into a function and live with it.

You better hope you have two or more items in the collection when you execute that code. And as Stefan says, your code is nearly as bad a way to do this as possible. I think the only worse way is to call ToArray. There are plenty of ways to do this well, and it baffles me that you choose the poor solution when good solutions exist. Does quality not matter?

Share this post


Link to post

Please let's agree to disagree.

 

My solution works for my specific problem and is easy to understand. It's also fast enough for me and since there is no multithreading involved temporarily changing the stack doesn't matter. Quality does indeed matter, but only as far as it makes any difference to the problem at hand.

This is basically a throw away program which I hope I will never have to use again (yeah, right, dream on).

Share this post


Link to post
On 11/28/2022 at 11:22 AM, programmerdelphi2k said:

i := MyStackList.Count - 2; // before last     if (i >= 0) then   getting obj =  MyStackList.List[ ...i...] 

@dummzeuch this dont help you? see above

Share this post


Link to post
On 11/28/2022 at 2:03 PM, dummzeuch said:

Yeah. I've been there: "It's simple, I'll write my own". [writes his own, overlooks a corner case and then takes 5 hours to find that bloody bug]

 

35 minutes ago, dummzeuch said:

This is basically a throw away program which I hope I will never have to use again (yeah, right, dream on).

 

It's almost as if posts from two completely different threads have somehow been interspersed with each other

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×