Converting 'list of Foo' into 'lists of Foo properties'

I'm looking at some code that goes a bit like this:

class Foo { public int Frob; public int Frib; }
class Bar { public Foo Left; public Foo Right; }

public void ProcessBars(Bar[] bars)
{
this.LeftFrobs = new int[bars.Count];
this.RightFrobs = new int[bars.Count];
this.LeftFribs = new int[bars.Count];
this.RightFribs = new int[bars.Count];
//... you get the idea

int counter = 0;
foreach(Bar bar in bars)
{
LeftFrobs[counter] = bar.Left.Frob;
LeftFribs[counter] = bar.Left.Frib;
//...27 more lines of similar
if(bar.Left.Frob == MAGICNUM_A) LeftFribs[counter] = MAGICNUM_B;

RightFrobs[counter] = bar.Right.Frob;
RightFribs[counter] = bar.Right.Frib;
//...27 more lines of similar
if(bar.Right.Frob == MAGICNUM_C) LeftFribs[counter] = MAGICNUM_D;

counter++;
}
}


Aesthetically, this bothers me, but so far, I haven't managed to come up with anything better.

• I don't understand, why do you have 27 more lines like that? Do you mean Foo and Bar have more properties? How exactly do you use the arrays after you create them? I mean, why do you need an array for each combination? – svick Sep 19 '12 at 12:40
• @svick, yes, more properties. You're right about usage. I think it's to dump them as columns into Excel (via a wrapper which likes columns), but I haven't got that far yet. I'm just trying to refactor this bit into something manageable. Currently looking at reducing to two properties Left and Right of Data { Frobs, Fribs }... – Benjol Sep 19 '12 at 12:49
• I don't think doing it that way would work well. If you have 60 fields, then the best way to set them is probably to have a line of code for each fields. On the other hand, having 60 fields is probably not the way to do this. But to know how to fix that, you will need to know how are they used. – svick Sep 19 '12 at 13:01

That method is immense, and is surely impossible to easily read and maintain. Once you break it into smaller methods you will be able to work with it ("just like those acorns, one at a time").
This will also help avoid repetitions of code.

I propose creating a class to hold all that data, and merely instantiate a Left and a Right objects of that class. Then move the loading of data into the class as well.

Then the foreach is limited to 3 lines plus all the ifs:

public class WildGooseChaser
{
class Foo { public int Frob; public int Frib; }
class Bar { public Foo Left; public Foo Right; }

private InternalData Left;
private InternalData Right;

class InternalData
{
public int[] Frobs;
public int[] Fribs;
// ... 27 more lines of similar.

public InternalData(int dataLength) {
Frobs = new int[dataLength];
Fribs = new int[dataLength];
//... you get the idea
}

public void LoadBar(int index, Bar bar) {
Frobs[index] = bar.Left.Frob;
Fribs[index] = bar.Left.Frib;
//...27 more lines of similar
}
}

public void ProcessBars(Bar[] bars) {
Left = new InternalData(bars.Length);
Right = new InternalData(bars.Length);

int counter = 0;
foreach (Bar bar in bars) {

if (bar.Left.Frob == MAGICNUM_A) {
Left.Fribs[counter] = MAGICNUM_B;
}

if (bar.Right.Frob == MAGICNUM_C) {
Left.Fribs[counter] = MAGICNUM_D;
}

counter++;
}
}
}


If you receive an array, you can use for instead of foreach.
So you can either get rid of the counter variable, or receive an IEnumerable<Bar> instead.

• Very nice. I was already part of the way there, but hadn't got as far as pulling the common logic into the data class. – Benjol Sep 19 '12 at 13:10
• It's actually a list, but I'm always in two minds about for when I also need to access the objects: for i with added bar = bars[i], or foreach with index++, or even Select((bar, index) =>... – Benjol Sep 19 '12 at 13:15
• Sorry, that's three minds :) – Benjol Sep 19 '12 at 13:23