2

Say I have a class or a struct defined as so:

public class foo
{
   public int x;
   public int y;
}

or 

public struct bar
{
   public int x;
   public int y;
}

Say I have some array or list of objects, either an array of foo's or bar's. Now I want to create an array or list of the x's and/or y's. Is there a simple way to do this in C# that does not require iterating through every foo or bar of the array, and then adding the desired member variable to another array?

For example, this is how I am currently doing it:

//For some List<foo> fooList
//get the x's and store them to the array List<int> xList

foreach (var fooAtom in fooList)
{
   xList.Add(fooAtom.x);
}

Is there a faster/less coding way of doing this? Is there a construct within C# designed specifically for this? Is it different for classes vs. structs? Thanks.

Iowa15
  • 3,027
  • 6
  • 28
  • 35

3 Answers3

3

You could use LINQ query:

Int32[] xArray = fooList.Select(fooItem => fooItem.x).ToArray();

This LINQ query will work the same way for both the classes and structs. But struct values can be boxed in some cases and they will be copied multiple times(they are structs at the end - passed by value) - that all will cause possible overhead for huge structures with multiple LINQ operations upon them.

Also take into account that LINQ is not the tool for every possible situation. Sometimes plain for(while) loop will be much more readable and will provide greater performance.

Community
  • 1
  • 1
Eugene Podskal
  • 10,270
  • 5
  • 31
  • 53
  • Read http://stackoverflow.com/questions/11344019/linq-and-lambda-expression and http://msdn.microsoft.com/en-us/library/bb397687.aspx. In short: each item in your list will be represented as `fooItem`, and from each this `fooItem` the `.x` field will be taken, and all those x fields will be united in one array. – Eugene Podskal Jul 08 '14 at 16:59
  • 2
    This involves no boxing at all. It does *copy* them, which is entirely different. (And also what the OP specifically said he didn't want to do.) – Servy Jul 08 '14 at 17:03
  • @Iowa15 Note that by doing `ToArray()`, you're making a new collection of integers, and it no longer remains up to date with the original `fooList`. If you simply use `var allXs = fooList.Select(f => f.x);`, `allXs` will stay "up to date" when you add or remove members from `fooList` (since it is basically an abstraction of an iteration over `fooList`) – Asad Saeeduddin Jul 08 '14 at 17:34
1

If they have something in common, you could also create an itnerface

public interface IFooBarable
{
    int x;
    int y;
}

and then your collection would just be a List<IFooBarable> in which you could hold your both Foo and Bar objects, and they could be accessed same way.

Tarec
  • 3,268
  • 4
  • 30
  • 47
1

I would make a base class or interface that has the x and y properties. This could allow for more flexibility in iterating the collections:

public interface IHasXY { int x { get; } int y { get; } }

public class Foo : IHasXY { public int x { get; set; } public int y { get; set; } }
public struct Bar : IHasXY { public int x { get; set; } public int y { get; set; } }

Then you can even concat foo and bar collections:

var allXs = fooList.Concat(barList).Select(o => o.x).ToArray();
itsme86
  • 19,266
  • 4
  • 41
  • 57