tags:

views:

155

answers:

4

Hi,

I have an object with large number of similar fields (like more than 10 of them) and I have to assign them values from an array of variable length. The solution would be either a huge nested bunch of ifs based on checking length of array each time and assigning each field

OR

a chain of ifs checking on whether the length is out of bounds and assigning each time after that check.

Both seem to be repetitive. Is there a better solution ?

+4  A: 

If you language has switch/case with fallthrough, you could do it like this:

switch(array.length){
    case 15: field14 = array[14];
    case 14: field13 = array[13];
    case 13: field12 = array[12];
    // etc.
    case 1: field0 = array[0];
    case 0: break;
    default: throw Exception("array too long!");
}
Michael Borgwardt
if it is case 15, i need to assign all way from 15 to 0... and continue like that.
Icarus
@Icarus: due to the fallthrough in switch/case, the code above *will* assign all 15 fields when the array has a length of 15
Michael Borgwardt
I was using c# and fall through does not work in it. I had to use case to make this happen. Also, had tried using var args but C# does not allow use of params with ref.
Icarus
+1  A: 
for (int i = 0; i < fieldCount; i++)
    fields[i].value = array[i];

That is to say, maintain an array of fields that corresponds to your array of values.

Carl Manaster
I really don't think this answers the question. The whole point is that he's trying to apply these values to the fields *of a class/object*. Making all of the fields special types with their own `value` properties and making them indexable (and safe) is exactly the problem he's trying to solve, just redefined as something much more complicated.
Aaronaught
But if you've created the field array - through whatever means - then you can simply apply it, as I've done above. Versus solving that same problem at many points in the code. Do the work of making them indexable and safe once, then use the product to simplify the code. That's all I'm saying.
Carl Manaster
If you defined this as the creation of an indexer property, or some similar *specific* solution, I might agree. As it is, though, you're suggesting to solve the problem of mapping an array to fields by creating another array... which then has to be mapped to the exact same fields.
Aaronaught
The problem here is that I don't have the fields Array.
Icarus
+1  A: 

If your language supports delegates, anonymous functions, that sort of thing, you can use those to clean it up. For example, in C# you could write this:

string[] values = GetValues();
SomeObject result = new SomeObject();
Apply(values, 0, v => result.ID = v);
Apply(values, 1, v => result.FirstName = v);
Apply(values, 2, v => result.LastName = v);
// etc.

The apply method would look like:

void Apply(string[] values, int index, Action<string> action)
{
    if (index < values.Length)
        action(values[index]);
}

This is obviously language-dependent, but something to think about regardless.


Another very simple option that we might be overlooking is, if you are actually trying to initialize an object from this value array (as opposed to update an existing object), to just accept the default values if the array isn't large enough.

C# example:

void CreateMyObject(object[] values)
{
    MyObject o = new MyObject();
    o.ID = GetValueOrDefault<int>(values, 0);
    o.FirstName = GetValueOrDefault<string>(values, 0);
    o.LastName = GetValueOrDefault<string>(values, 0);
    // etc.
}

void GetValueOrDefault<T>(object[] values, int index)
{
    if (index < values.Length)
        return (T)values[index];
    return default(T);
}

Sometimes the dumb solution is the smartest choice.

Aaronaught
That could be made cleaner by creating an array of delegates and looping through them.
Hosam Aly
@Hosam Aly: Not really, you're just going to have to write the same code I've already written to create the array. Unless you're doing this in more than one place, it doesn't save anything.
Aaronaught
It would at least save having to write the function invokation so many times, in addition to a variable for tracking indices. It would also be easier to update it if the object structure is updated, IMHO.
Hosam Aly
@Hosam Aly: Nothing is made easier unless this code is being used in several places, which the question does not state. If it's only done once, or once per class/array pair, then you end up writing *more* code just to initialize an unnecessary array.
Aaronaught
A: 

If your fields are declared in the same order of the array's elements, you could use reflection (if available in your language) to set these values. Here is an example of how you could do it in Java:

// obj is your object, values is the array of values
Field[] fields = obj.getClass().getFields();
for (int i = 0; i < fields.length && i < values.length; ++i) {
    fields[i].set(obj, values[i]);
}
Hosam Aly
This seems incredibly unlikely, and outright dangerous even if it's true. A simple refactoring of the class would break this and you wouldn't know it until runtime; you might not even get a runtime error, you'd just end up with corrupt data. You should never rely on the order of field declarations in a class.
Aaronaught
I agree that it's pretty dangerous, but if you come from a Python background then you might find it acceptable. Anyway, it's a tool that can be used for good or evil.
Hosam Aly
I didnt want to use this because of not being sure that reflection will give me the fields in same order as those declared in class. Is that always the case ?
Icarus
@Icarus: No, the documentation explicitly says that the order is not guaranteed. However, you could sort them in a predictable order. Check this other question for more information: http://stackoverflow.com/questions/1097807/java-reflection-is-the-order-of-class-fields-and-methods-standardized
Hosam Aly