tags:

views:

104

answers:

5

I have a collection of say 8 elements. I want to traverse it in such a way, that after 2 iterations I do something else, and then back to traversing.

A practical application is making a layout. I lay two square boxes, then I print a new line, and then I lay two square boxes.

is there a way I can make a sequence collection into something like this using Linq? Maybe using the Group by clause? Can't think of a solution though.

Collection --> "1, 2, 3, 4, 5, 6, 7, 8"

Want to print like

1 2

3 4

5 6

7 8

A: 
SLaks
I'd love to see the abusive aggregate solution.
halivingston
A: 

could you do something that uses skip and take

collection.Take(2) - takes first 2 elements
collection.Skip(2).Take(2) - skips first 2 and takes elements 3 and 4 

etc

i am not sure of the code that you have but im sure this may help if you can use it

PaulStack
This will involve significant extra enumeration.
SLaks
+2  A: 

Use an extension method such as the following:

public static IEnumerable<Tuple<TElement, TElement>> AsPairs<TElement>(this IEnumerable<TElement> @this)
{
    IEnumerator<TElement> enumerator = @this.GetEnumerator();

    while (enumerator.MoveNext())
    {
        TElement left = enumerator.Current;

        if (enumerator.MoveNext())
        {
            TElement right = enumerator.Current;

            yield return Tuple.Create(left, right);
        }
        else
        {
            throw new ArgumentException("this", "Expected an even number of elements.");
        }
    }
}

...
foreach (Tuple<TextBox, TextBox> pair = textBoxes.AsPairs())
{
    ...
}

Edit: Added exception in uneven enumerable case.

Paul Ruane
Metaphorical +1. Excellent.
halivingston
Tuple is .NET 4.0, let me try there .. should work, I'll probably grab a touple for .net 3.5 from somewhere.
halivingston
also, what is the @ symbol for .. no exceptions?
halivingston
That's a good solution. I first thougt of getting all elements with a even index via an Where-clause and then using Zip like this: even.Zip(elements.Except(even), (a, b) => new { a=a, b=b});
dkson
But his would propably not work in all situations, since Where/Except can destroy your ordering IIRC
dkson
@haliving, the @ symbol allows you to use a keyword as an identifier
Thomas Levesque
ohh .. that's not a good practice, but who cares, i'll change it from this ... to thisCollection or something
halivingston
@haliving: I use '@this' for the target object in extension methods because, by writing an extension method, one is creating a synthetic member method. The target object is therefore the 'this' object had you have written the method as a genuine member method.
Paul Ruane
Is there a way to return the index you're currently @?
halivingston
@haliving: Yes, either add a counter variable or switch to a 'for' loop (or look up the 'foreach' extension method that returns an index as a delegate/lambda parameter).
Paul Ruane
A: 

Here's your solution

    private static void TraverseInTwos()
    {
        var col = new Collection<int> { 1, 2, 3, 4, 5, 6, 7, 8 };
        int i = 0;
        while (col.Skip(i).Any())
        {
            var newCol = col.Skip(i).Take(2);
            Console.WriteLine(newCol.First() + " " + ((newCol.Count() > 1) ? newCol.Last().ToString() : string.Empty));
            i += 2;
        }
    }
danijels
That's unreadable and very slow IMHO
dkson
It might be a matter of habit, but in any case, OP asked for a linq-based solution and I provided one. Performs ok actually.
danijels
Of course it performs OK -- you only have 8 elements. Try it with 1,000,000 elements and see if it's still OK.
Gabe
A: 

Here you go :)

var ten = Enumerable.Range(20, 10);
var pairs = ten.Select((i,index) => new { group = (index >> 1), val = i }).GroupBy(a => a.group);

foreach (var pair in pairs)
{
    foreach (var i in pair) Console.Write(i.val + " ");
    Console.WriteLine();
}

/Moberg

Moberg