2

I was trying to make a function that returns a boolean: true if all items are the same, false if not. I tought to use a foreach loop to iterate the stack and somehow check if all items are equal or not, but I'm not sure this is the best way.

What i tried is:

bool AllSame(Stack<int> myStack)
{
    int check = myStack.Peek();
    foreach(int i in myStack)
        if(i != check)
            return false;
    return true;
}

The example above was made with integer values to make things simple, but of course these could be any generic values

  • Does this answer your question? [How to get stack items by index in c#?](https://stackoverflow.com/questions/38535026/how-to-get-stack-items-by-index-in-c) – teddyzhng Aug 16 '23 at 21:26
  • 1
    `Stack` implements `IEnumerable`. Have you tried using a foreach or LINQ on the Stack itself? – gunr2171 Aug 16 '23 at 21:29
  • 1
    Does this answer your question? [Check if all items are the same in a List](https://stackoverflow.com/questions/5307172/check-if-all-items-are-the-same-in-a-list) – gunr2171 Aug 16 '23 at 21:33
  • What does "the best way" mean? Fastest, shortest, easiest to understand, easiest to maintain? – NetMage Aug 16 '23 at 21:41
  • Kind of begs the question why you are using a stack in the first place. – Charlieface Aug 16 '23 at 21:53

1 Answers1

0

This seems like a reason to write your own extension method. When writing a LINQ extension method with some unusual element processing (in this case, treat the first element specially) using an Enumerator directly is probably best.

public static class StackExt {
    public static bool AllSame<T>(this Stack<T> s, IEqualityComparer<T> cmp = null) {
        cmp ??= EqualityComparer<T>.Default;
        var se = s.GetEnumerator();
        if (se.MoveNext()) {
            T first = se.Current;
            while (se.MoveNext())
                if (!cmp.Equals(first, se.Current))
                    return false;
        }

        return true;
    }

    public static bool AllSame2<T>(this Stack<T> s, IEqualityComparer<T> cmp = null) => s.Distinct(cmp).Take(2).Count() == 1;
}

I also included a LINQ version of the extension method: the LINQ version is shorter, but not as efficient as it has to allocate a Set<T> to track what has been seen to implement Distinct(), though the Take(2) limits the worst performance issue, which is that Count() would count all of the elements when you only care if there is one or more than one.

NetMage
  • 26,163
  • 3
  • 34
  • 55
  • 1
    Would it be better to use `All` instead of `Distinct`? `s.All(x => cmp.Equals(x, s.First()))` would simply iterate and short-circuit when it first encounters a different item. – NPras Aug 17 '23 at 04:42
  • @NPras You would need to cache `s.First()` instead of calling it per comparison and you would need to handle default for `cmp` - `Stack` doesn't implement any special cases so `First()` has to create an iterator and iterate to the first item. `s.First() is var first && (cmp ?? EqualityComparer.Default) is var ucmp && s.All(x => ucmp.Equals(x, first))` You are also doing an unnecessary comparison of `first` against `first`. Probably a wash. – NetMage Aug 17 '23 at 18:57