2

I have a collection of items that I want to transform (basically, wrap in metadata). For the first item in the collection, I simply wrap the necessary metadata around the item and I'm done. The second item's metadata is dependent on the previous item's metadata, so I want to pass the first item's metadata to the second item.

The following....

object[] A;

A.skip(1)
 .Zip( A, (first, second), a => new Metadata( first, second ) );

...will not work because it's using object as the second input rather than Metadata. This is true for every other solution I've seen so far (passing the original object, rather than the result of the Select() function).

How would I feed the result of the Select() for the first item in my LINQ query into the Select() for the second item?

I know I could use a for loop to accomplish this, but I'm wondering if there isn't a more functional way of handling this kind of problem. There must be a solution in functional style languages such as F# and I'm wondering if I could translate that into a LINQ solution in C#. A one-liner solution would be especially awesome.

By chaining the metadata together like this, I can pass along important information from one item to all of the following items, such as flags or context. The goal, ultimately, is not just to know about the previous item, but about the whole context of the current item. The current item can then change the context for all following items, etc.

BenMorel
  • 34,448
  • 50
  • 182
  • 322
JDB
  • 25,172
  • 5
  • 72
  • 123

2 Answers2

2

Try .Aggregate().

var data = A.Aggregate(new Metadata(null, A), (meta, a) => new Metadata(meta, a));

I won't gurantee that I have the syntax for that right, especially not for your code. The idea should be clear, though, and if you edit in a more thorough example, I can expand on this.

Bobson
  • 13,498
  • 5
  • 55
  • 80
  • I think this is right, except it would only yield the last value of the sequence. – MisterMetaphor Jun 27 '13 at 13:54
  • @MisterMetaphor - There's [another version](http://msdn.microsoft.com/en-us/library/bb548744.aspx) of it which takes an extra argument for a function to produce the result. That might be what's needed. Also, thanks for catching the `Accumulate` -> `Aggregate`. I always do that. – Bobson Jun 27 '13 at 14:02
  • You can see from the method signature that it returns a single value as well. I might be mistaken but I think the OP is trying to get a sequence of items as a result. – MisterMetaphor Jun 27 '13 at 14:05
  • @MisterMetaphor - You were correct... I should have made that more clear in my question. – JDB Jun 27 '13 at 14:33
1

This kind of behavior is usually accomplished with a scan or similar function in functional programming languages. In F#, you can do it like this:

originalSequence |> Seq.scan (fun (prev, current) -> Some <| new Metadata( (* ... stuff ... *) )) None

See this question for an implementation of a Scan extension method in C#. Given that method, you can implement your query like this:

A.Scan((previous, current) => new Metadata(/* ... */), null)

Can't think of an elegant one-liner implementation of the Scan method though.

Community
  • 1
  • 1
MisterMetaphor
  • 5,900
  • 3
  • 24
  • 31
  • Thanks! In case you are curious, I've applied this function to [this question/answer](http://stackoverflow.com/a/17345950/211627). – JDB Jun 27 '13 at 14:39