Calling IEnumerable<T>

Shurik

New member
Joined
May 5, 2022
Messages
4
Programming Experience
10+
Hi,

Could someone please help with the following?

I'm not a C#-programmer and would like to get the code below working.

How could I call MergeShuffle<T> in this case.

Thank you very much in advance,

Kind Regards,

Shurik.


C#:
using System;
using System.Collections.Generic;


namespace ShuffleLists
{
    class Program
    {
        static void Main(string[] args)
        {

            List<Int16> lista = new List<Int16>();
            lista.Add(1);
            lista.Add(3);
            lista.Add(5);
            lista.Add(7);

            List<Int16> listb = new List<Int16>();
            listb.Add(2);
            listb.Add(4);
            listb.Add(6);
            listb.Add(8);


            // how would I call MergeShuffle<T> with the above 2 lists, please?
            
                        
            //var list_merged = MergeShuffle(lista,listb);

        }


        //courtesy of https://stackoverflow.com/questions/11296810/how-do-i-implement-ienumerablet
        static IEnumerable<T> MergeShuffle<T>(IEnumerable<T> lista, IEnumerable<T> listb)
        {
            var first = lista.GetEnumerator();
            var second = listb.GetEnumerator();

            var rand = new Random();
            bool exhaustedA = false;
            bool exhaustedB = false;
            while (!(exhaustedA && exhaustedB))
            {
                bool found = false;
                if (!exhaustedB && (exhaustedA || rand.Next(0, 2) == 0))
                {
                    exhaustedB = !(found = second.MoveNext());
                    if (found)
                        yield return second.Current;
                }
                if (!found && !exhaustedA)
                {
                    exhaustedA = !(found = first.MoveNext());
                    if (found)
                        yield return first.Current;
                }
            }
        }

    }
 
You ask a use a question that you already have an answer to because it's in your own code, commented out. Uncomment that line and you have called the method. I suspect that the actual question you want answered is how you then use the result of that method. I'm not going to answer that based on a guess though. If that's actually what you want to know, that's what you should ask, after explaining exactly what it is that you're trying to achieve.
 
Hi,

Thank you for the prompt reply.
Yes, you're right, the question is about returning/using the output ('shuffled' list)
Now I just get 'The program '[17144] ConsoleApp2.exe' has exited with code 0 (0x0).'-message with no results

Kind regards,
Shurik.
 
How you use it depends on what you want to accomplish. What do you want to accomplish? What "results" do you want to see? Are you saying, without actually saying, that you want to display results in the console? In that case, how would you do that with any other list? You would, most likely, use a foreach loop and write each item out to its own line. This is no different. The method returns an IEnumerable<T> which means that you can enumerate the list, which basically means you can run a foreach loop over it. If you need a concrete list that you can pass around then you can call ToArray or ToList on it.
 
I would have implemented MergeShuffle<T>() this way:
C#:
static IEnumerable<T> MergeShuffle<T>(IEnumerable<T> listA, IEnumerable<T> listB)
{
    var queues = new[] { new Queue<T>(listA), new Queue<T>(listB) };
    var random = new Random();

    while (queues.Any(q => q.Count > 0))
    {
        int @this = random.Next(0, 2);
        int @that = (@this + 1) % 2;

        if (queues[@this].TryDequeue(out T item) || queues[@that].TryDequeue(out item))
            yield return item;
    }
}

It admittedly has the overhead of pull all the items out the two input enumerables first before it starts spitting out values. The implementation in the OP is more efficient about only getting items as needed.

And if I truly need to get rid of that overhead, then I'll implement this cheap queue:
CheapQueue:
class CheapQueue<T>
{
    public bool HasMore { get; private set; } = true;
    IEnumerator<T> _enum;

    public CheapQueue(IEnumerable<T> list)
        => _enum = list.GetEnumerator();

    public bool TryDequeue(out T item)
    {
        item = default(T);
        if (HasMore)
        {
            if (_enum.MoveNext())
                item = _enum.Current;
            else
                HasMore = false;
        }
        return HasMore;
    }
}

which in the end is basically what is in the OP, but written in an object oriented way rather a procedural way.
 
Last edited:
Just for fun, I decided to generalise that method to any number of lists:
C#:
static IEnumerable<T> MergeShuffle<T>(params IEnumerable<T>[] lists)
{
    var random = new Random();

    // Create a queue from each list, so items can be removed one by one.
    var queues = lists.Select(l => new Queue<T>(l)).ToArray();

    T item = default;

    // Randomise the queues and remove an item from the first queue that still has items, if any.
    while (queues.OrderBy(q => random.NextDouble()).Any(q => q.TryDequeue(out item)))
    {
        yield return item;
    }
}
Sample usage:
C#:
var arr1 = new[] {1, 2, 3};
var arr2 = new[] {4, 5, 6};

Console.WriteLine(string.Join(", ", MergeShuffle(arr1, arr2)));

var arr3 = new[] {7, 8, 9};
var arr4 = new[] {10, 11, 12};

Console.WriteLine(string.Join(", ", MergeShuffle(arr1, arr2, arr3, arr4)));
 
Back
Top Bottom