|
ms
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
LINQ and data projectioninto a new data type. For example, I have this array: string[] myString = {"1.0", "2.0", "3.0", "7.0", "8.0", "9.0"}; I would like to project this data into a vertex struct: struct Vertex { public Vertex(float a, float b, float c){x=a;y=b;z=c;} float x, y, z; }; Here's a for loop that will do it, but I'd like to figure it out with LINQ: for(int i = 0 ; i < myString.Length ; i += 3) Vertex v = new Vertex(myString[i], myString[i + 1], myString[i + 2]); Thanks for any help. Gary Nastrasio wrote:
Show quoteHide quote > I have an array of data and I would like to project every 3 elements if a 2-line loop statement which is perfectly clear and readable does > into a new data type. > > For example, I have this array: > > string[] myString = {"1.0", "2.0", "3.0", "7.0", "8.0", "9.0"}; > > > I would like to project this data into a vertex struct: > > struct Vertex > { > public Vertex(float a, float b, float c){x=a;y=b;z=c;} > float x, y, z; > }; > > > Here's a for loop that will do it, but I'd like to figure it out with LINQ: > > for(int i = 0 ; i < myString.Length ; i += 3) > Vertex v = new Vertex(myString[i], myString[i + 1], myString[i + 2]); the trick, why trying to do it with linq, which likely will also be at least as complex (if possible at all)? FB -- ------------------------------------------------------------------------ Lead developer of LLBLGen Pro, the productive O/R mapper for .NET LLBLGen Pro website: http://www.llblgen.com My .NET blog: http://weblogs.asp.net/fbouma Microsoft MVP (C#) ------------------------------------------------------------------------ >> You're absolutely right about the loop being clear and readable. I >> Here's a for loop that will do it, but I'd like to figure it out with >> LINQ: >> >> for(int i = 0 ; i < myString.Length ; i += 3) >> Vertex v = new Vertex(myString[i], myString[i + 1], myString[i + 2]); > > if a 2-line loop statement which is perfectly clear and readable > does the trick, why trying to do it with linq, which likely will also be > at least as complex (if possible at all)? > > FB > wanted to try using LINQ for the simple reason of increasing my LINQ skill level. Gary Nastrasio wrote:
Show quoteHide quote >>> Heh, then this particular task will definitely increase your skill >>> Here's a for loop that will do it, but I'd like to figure it out with >>> LINQ: >>> >>> for(int i = 0 ; i < myString.Length ; i += 3) >>> Vertex v = new Vertex(myString[i], myString[i + 1], myString[i + 2]); >> >> if a 2-line loop statement which is perfectly clear and readable >> does the trick, why trying to do it with linq, which likely will also >> be at least as complex (if possible at all)? >> >> FB >> > > You're absolutely right about the loop being clear and readable. I > wanted to try using LINQ for the simple reason of increasing my LINQ > skill level. level, because IMHO it's pretty hard to do, at first glance. I haven't looked at it more closely, but I think it's pretty hard to do this in linq, because of the skipping part you have to do after you've read 3 elements from the sequence. I can think of a way with ElementAt(n), but that is extremely inefficient (it seeks with every element), or with a 3-query process where you project the top element of the sequence into a new anonymous type together with the rest of the sequence (although that also sounds like impossible). I've done a lot of linq-to-objects queries in the past months and my experience is that for some things it's really handy, and one should definitely use it for these situations, but in other situations, like where it takes a while before you see how it should be done, it's often easier to simply go for a loop, as that gets the thing done as well. FB -- ------------------------------------------------------------------------ Lead developer of LLBLGen Pro, the productive O/R mapper for .NET LLBLGen Pro website: http://www.llblgen.com My .NET blog: http://weblogs.asp.net/fbouma Microsoft MVP (C#) ------------------------------------------------------------------------
Show quote
Hide quote
"Frans Bouma [C# MVP]" <perseus.usenetNOSPAM@xs4all.nl> wrote in message This is an interesting problem though and its definitely a good exercise news:OOvkJg1YJHA.4480@TK2MSFTNGP06.phx.gbl... > Gary Nastrasio wrote: >>>> >>>> Here's a for loop that will do it, but I'd like to figure it out with >>>> LINQ: >>>> >>>> for(int i = 0 ; i < myString.Length ; i += 3) >>>> Vertex v = new Vertex(myString[i], myString[i + 1], myString[i + >>>> 2]); >>> >>> if a 2-line loop statement which is perfectly clear and readable >>> does the trick, why trying to do it with linq, which likely will also be >>> at least as complex (if possible at all)? >>> >>> FB >>> >> >> You're absolutely right about the loop being clear and readable. I >> wanted to try using LINQ for the simple reason of increasing my LINQ >> skill level. > > Heh, then this particular task will definitely increase your skill level, > because IMHO it's pretty hard to do, at first glance. I haven't looked at > it more closely, but I think it's pretty hard to do this in linq, because > of the skipping part you have to do after you've read 3 elements from the > sequence. I can think of a way with ElementAt(n), but that is extremely > inefficient (it seeks with every element), or with a 3-query process where > you project the top element of the sequence into a new anonymous type > together with the rest of the sequence (although that also sounds like > impossible). > > I've done a lot of linq-to-objects queries in the past months and my > experience is that for some things it's really handy, and one should > definitely use it for these situations, but in other situations, like > where it takes a while before you see how it should be done, it's often > easier to simply go for a loop, as that gets the thing done as well. > that can help broaden ones knowledge of LINQ. I've been trying to solve this for the general case where all that is known of the data source is that its an IEnumerable<T>. In this case indexers are not available. Of course direct usuage of the Enumerator returned by GetEnumerator could be used but I'm wondering if a solution can be described in LINQ or with the extension methods and Lambda's. So far I've failed miserably. -- Anthony Jones - MVP ASP/ASP.NET
Show quote
Hide quote
"Anthony Jones" <AnthonyWJo***@yadayadayada.com> wrote in message This seems pretty sucessful and readable:-news:%23K$DYt3YJHA.4852@TK2MSFTNGP04.phx.gbl... > "Frans Bouma [C# MVP]" <perseus.usenetNOSPAM@xs4all.nl> wrote in message > news:OOvkJg1YJHA.4480@TK2MSFTNGP06.phx.gbl... >> Gary Nastrasio wrote: >>>>> >>>>> Here's a for loop that will do it, but I'd like to figure it out with >>>>> LINQ: >>>>> >>>>> for(int i = 0 ; i < myString.Length ; i += 3) >>>>> Vertex v = new Vertex(myString[i], myString[i + 1], myString[i > > This is an interesting problem though and its definitely a good exercise > that can help broaden ones knowledge of LINQ. > > I've been trying to solve this for the general case where all that is > known > of the data source is that its an IEnumerable<T>. In this case > indexers are not available. Of course direct usuage of the Enumerator > returned by GetEnumerator could be used but I'm wondering if a solution > can be described in LINQ or with the extension methods and Lambda's. > > So far I've failed miserably. > struct Vertex { public int x { get; private set; } public int y { get; private set; } public int z { get; private set; } public Vertex(int a, int b, int c) : this() { x = a; y = b; z = c; } } var x = from i in Enumerable.Range(1, 9) group i by (i - 1) / 3 into g let v = g.ToArray() select new Vertex(v[0], v[1], v[2]); foreach (var v in x) Console.WriteLine("x: {0}, y: {1}, z: {2}", v.x, v.y, v.z); It would be nice to avoid the ToArray() though. -- Anthony Jones - MVP ASP/ASP.NET Anthony Jones wrote:
Show quoteHide quote > "Anthony Jones" <AnthonyWJo***@yadayadayada.com> wrote in message Easy enough, though it's hardly elegant:> news:%23K$DYt3YJHA.4852@TK2MSFTNGP04.phx.gbl... >> "Frans Bouma [C# MVP]" <perseus.usenetNOSPAM@xs4all.nl> wrote in >> message news:OOvkJg1YJHA.4480@TK2MSFTNGP06.phx.gbl... >>> Gary Nastrasio wrote: >>>>>> >>>>>> Here's a for loop that will do it, but I'd like to figure it out >>>>>> with LINQ: >>>>>> >>>>>> for(int i = 0 ; i < myString.Length ; i += 3) >>>>>> Vertex v = new Vertex(myString[i], myString[i + 1], myString[i > >> This is an interesting problem though and its definitely a good >> exercise that can help broaden ones knowledge of LINQ. >> >> I've been trying to solve this for the general case where all that is >> known > of the data source is that its an IEnumerable<T>. In this >> case indexers are not available. Of course direct usuage of the >> Enumerator returned by GetEnumerator could be used but I'm wondering >> if a solution can be described in LINQ or with the extension methods >> and Lambda's. >> >> So far I've failed miserably. >> > > This seems pretty sucessful and readable:- > > struct Vertex > { > public int x { get; private set; } > public int y { get; private set; } > public int z { get; private set; } > public Vertex(int a, int b, int c) : this() { x = a; y = b; z = c; } > } > > var x = from i in Enumerable.Range(1, 9) > group i by (i - 1) / 3 into g > let v = g.ToArray() > select new Vertex(v[0], v[1], v[2]); > > foreach (var v in x) > Console.WriteLine("x: {0}, y: {1}, z: {2}", v.x, v.y, v.z); > > It would be nice to avoid the ToArray() though. > var flatVertices = new double[] { 1.0, 2.0, 3.0, 7.0, 8.0, 9.0 }; var vertices = from v in flatVertices.Select((f, i) => new { f, i = i / 3 }) group v by v.i into g let x = g.First().f let yg = g.Skip(1) let y = yg.First().f let zg = yg.Skip(1) let z = zg.First().f select new Vertex(x, y, z); It's not really possible to do this elegantly in LINQ (OK, so you might get something if you throw in recursion, but I honestly wouldn't bother). Use a real functional language like F#, so you get the benefits of arbitrary tuples and pattern matching. -- J.
Show quote
Hide quote
"Jeroen Mostert" <jmost***@xs4all.nl> wrote in message If elegance was the only criteria then the my existing attempt is pretty news:494e9b56$0$185$e4fe514c@news.xs4all.nl... > Anthony Jones wrote: >> "Anthony Jones" <AnthonyWJo***@yadayadayada.com> wrote in message >> news:%23K$DYt3YJHA.4852@TK2MSFTNGP04.phx.gbl... >>> "Frans Bouma [C# MVP]" <perseus.usenetNOSPAM@xs4all.nl> wrote in message >>> news:OOvkJg1YJHA.4480@TK2MSFTNGP06.phx.gbl... >>>> Gary Nastrasio wrote: >>>>>>> >>>>>>> Here's a for loop that will do it, but I'd like to figure it out >>>>>>> with LINQ: >>>>>>> >>>>>>> for(int i = 0 ; i < myString.Length ; i += 3) >>>>>>> Vertex v = new Vertex(myString[i], myString[i + 1], myString[i > >>> This is an interesting problem though and its definitely a good exercise >>> that can help broaden ones knowledge of LINQ. >>> >>> I've been trying to solve this for the general case where all that is >>> known > of the data source is that its an IEnumerable<T>. In this case >>> indexers are not available. Of course direct usuage of the Enumerator >>> returned by GetEnumerator could be used but I'm wondering if a solution >>> can be described in LINQ or with the extension methods and Lambda's. >>> >>> So far I've failed miserably. >>> >> >> This seems pretty sucessful and readable:- >> >> struct Vertex >> { >> public int x { get; private set; } >> public int y { get; private set; } >> public int z { get; private set; } >> public Vertex(int a, int b, int c) : this() { x = a; y = b; z = c; } >> } >> >> var x = from i in Enumerable.Range(1, 9) >> group i by (i - 1) / 3 into g >> let v = g.ToArray() >> select new Vertex(v[0], v[1], v[2]); >> >> foreach (var v in x) >> Console.WriteLine("x: {0}, y: {1}, z: {2}", v.x, v.y, v.z); >> >> It would be nice to avoid the ToArray() though. >> > Easy enough, though it's hardly elegant: > > var flatVertices = new double[] { 1.0, 2.0, 3.0, 7.0, 8.0, 9.0 }; > var vertices = > from v in flatVertices.Select((f, i) => new { f, i = i / 3 }) > group v by v.i into g > let x = g.First().f > let yg = g.Skip(1) > let y = yg.First().f > let zg = yg.Skip(1) > let z = zg.First().f > select new Vertex(x, y, z); > > It's not really possible to do this elegantly in LINQ good, its just that it would be nice not be creating and throwing away an array per vertex. >(OK, so you might get something if you throw in recursion, but I honestly F# may be a solution if someone could find a way to explain it properly to >wouldn't bother). >Use a real functional language like F#, so you get the >benefits of arbitrary tuples and pattern matching. > non-functional thinkers. What would an F# solution look like? -- Anthony Jones - MVP ASP/ASP.NET
Show quote
Hide quote
"Anthony Jones" <AnthonyWJo***@yadayadayada.com> wrote in message Actually taking a look at your code again it does fix a bug in my solution news:%23Qsp4h7YJHA.3548@TK2MSFTNGP05.phx.gbl... > "Jeroen Mostert" <jmost***@xs4all.nl> wrote in message > news:494e9b56$0$185$e4fe514c@news.xs4all.nl... >> Anthony Jones wrote: >>> "Anthony Jones" <AnthonyWJo***@yadayadayada.com> wrote in message >>> news:%23K$DYt3YJHA.4852@TK2MSFTNGP04.phx.gbl... >>>> "Frans Bouma [C# MVP]" <perseus.usenetNOSPAM@xs4all.nl> wrote in >>>> message news:OOvkJg1YJHA.4480@TK2MSFTNGP06.phx.gbl... >>>>> Gary Nastrasio wrote: >>>>>>>> >>>>>>>> Here's a for loop that will do it, but I'd like to figure it out >>>>>>>> with LINQ: >>>>>>>> >>>>>>>> for(int i = 0 ; i < myString.Length ; i += 3) >>>>>>>> Vertex v = new Vertex(myString[i], myString[i + 1], myString[i > >>>> This is an interesting problem though and its definitely a good >>>> exercise that can help broaden ones knowledge of LINQ. >>>> >>>> I've been trying to solve this for the general case where all that is >>>> known > of the data source is that its an IEnumerable<T>. In this case >>>> indexers are not available. Of course direct usuage of the Enumerator >>>> returned by GetEnumerator could be used but I'm wondering if a solution >>>> can be described in LINQ or with the extension methods and Lambda's. >>>> >>>> So far I've failed miserably. >>>> >>> >>> This seems pretty sucessful and readable:- >>> >>> struct Vertex >>> { >>> public int x { get; private set; } >>> public int y { get; private set; } >>> public int z { get; private set; } >>> public Vertex(int a, int b, int c) : this() { x = a; y = b; z = c; } >>> } >>> >>> var x = from i in Enumerable.Range(1, 9) >>> group i by (i - 1) / 3 into g >>> let v = g.ToArray() >>> select new Vertex(v[0], v[1], v[2]); >>> >>> foreach (var v in x) >>> Console.WriteLine("x: {0}, y: {1}, z: {2}", v.x, v.y, v.z); >>> >>> It would be nice to avoid the ToArray() though. >>> >> Easy enough, though it's hardly elegant: >> >> var flatVertices = new double[] { 1.0, 2.0, 3.0, 7.0, 8.0, 9.0 }; >> var vertices = >> from v in flatVertices.Select((f, i) => new { f, i = i / 3 }) >> group v by v.i into g >> let x = g.First().f >> let yg = g.Skip(1) >> let y = yg.First().f >> let zg = yg.Skip(1) >> let z = zg.First().f >> select new Vertex(x, y, z); >> >> It's not really possible to do this elegantly in LINQ > > If elegance was the only criteria then the my existing attempt is pretty > good, its just that it would be nice not be creating and throwing away an > array per vertex. > where the grouping value is all wrong. -- Anthony Jones - MVP ASP/ASP.NET Gary Nastrasio wrote:
Show quoteHide quote > I have an array of data and I would like to project every 3 elements LINQ does not seem to be the best tool to transform:> into a new data type. > > For example, I have this array: > > string[] myString = {"1.0", "2.0", "3.0", "7.0", "8.0", "9.0"}; > > > I would like to project this data into a vertex struct: > > struct Vertex > { > public Vertex(float a, float b, float c){x=a;y=b;z=c;} > float x, y, z; > }; > > > Here's a for loop that will do it, but I'd like to figure it out with LINQ: > > for(int i = 0 ; i < myString.Length ; i += 3) > Vertex v = new Vertex(myString[i], myString[i + 1], myString[i + 2]); 1.0 2.0 3.0 7.0 8.0 9.0 to: 1.0 2.0 3.0 7.0 8.0 9.0 which is the core of the problem. Arne "Gary Nastrasio" <garynastra***@hotmail.com> wrote in message Linq has a lot of holes that are not that difficult to come accross. If news:eFQaXPmYJHA.5108@TK2MSFTNGP05.phx.gbl... > Here's a for loop that will do it, but I'd like to figure it out with > LINQ: > > for(int i = 0 ; i < myString.Length ; i += 3) > Vertex v = new Vertex(myString[i], myString[i + 1], myString[i + 2]); you're going to use it you need to get used to the idea of adding your own linq functions. In this case you could write a function to grab a certain numer of elements from the source. The end result would look something like this. Note the conversion to integer which your original code doesn't have. myString.Select(i => Convert.ToInt32(i)).GrabChunk((i, j, k) => new Vertex(i, j, k)); The function would look something like this. Note I don't have vs2008 here to test this so some fixes will undoubtedly be needed. We can write a function for 2, 3 and 4 arguements, for obvious reasons we don't need one for 1 arguement :-) //for 2 arguements: public static IEnumerable<TResult> GrabChunk<TIn, TResult>(this IEnumerable<TIn> source, Func<TIn, TIn, TResult> selector) { IEnumerator<TIn> en = source.GetEnumerator(); TIn a, b; if(en.MoveNext()) { a = en.Current; if(en.MoveNext()) { b = en.Current; yield return selector(a, b); } } } //for 3 arguements: public static IEnumerable<TResult> GrabChunk<TIn, TResult>(IEnumerable<TIn> source, Func<TIn, TIn, TIn, TResult> selector) { IEnumerator<TIn> en = source.GetEnumerator(); TIn a, b, c; if(en.MoveNext()) { a = en.Current; if(en.MoveNext()) { b = en.Current; if(en.MoveNext()) { c = en.Current; yield return selector(a, b, c); } } } } Show quoteHide quote > > > > Thanks for any help.
Other interesting topics
Regex question
Multi threaded design patterns Mapping Combobox doesn't work if the form has TopMost = true how to convert a byte array with string,int and double embeded? Call Hierarchy Inherit Overrides Do SingleCall server activation objects retain state across calls? Linq.Table<variable> is it possible Linq To Sql: Contains any. |
|||||||||||||||||||||||