I'm starting with an IntPtr to structured data from a hardware source that sends periodic packets. A thread copies a packet from the Intptr buffer and places byte[] into a queue. Later the queue is read and byte[] is converted to a structure using this answer and becomes a collection (array) of type Packet.
struct Packet {
long time;
int field1;
short field2;
}
Packet[] array_of_packet;
Without duplicating the structure definition, I would like to use the data as if it was a structure of arrays.
struct ArrayOfPacket {
long[] time;
int[] field1;
short[] field2;
}
ArrayOfPacket data;
This format allows other functions use them as vectors:
Plot(data.time, data.field1);
If all you want is an easy way to transform to arrays, then just use LINQ:
Plot (array_of_packet.Select(p => p.time).ToArray(),
array_of_packet.Select(p => p.field1).ToArray());
If you're looking for a magic way to rearrange the data in memory without the cost of copying, then you're out of luck. ;-)
Pretty easy with Linq
data.time = array_of_packet.Select(p => p.time).ToArray();
data.field1 = array_of_packet.Select(p => p.field1).ToArray();
data.field2 = array_of_packet.Select(p => p.field2).ToArray();
Though you'll need to make the properties public
A more effecient solution might be
var time = new long[array_of_packet.Length];
var field1 = new int[array_of_packet.Length];
var field2 = new short[array_of_packet.Length];
for(int i = 0; i < array_of_packet.Length; i++)
{
time[i] = array_of_paket[i].time;
field1[i] = array_of_paket[i].field1;
field2[i] = array_of_paket[i].field2;
}
data.time = time;
data.field1 = field1;
data.field2 = field2;
You could create a wrapper class that exposes an array-like accessor syntax:
class ArrayWrapper<T, TField>
{
Func<T, TField> getField;
T[] array;
public ArrayWrapper(T[] array, Func<T, TField> getField)
{
this.array = array;
this.getField = getField;
}
public TField this[int index]
{
get { return this.getField(this.array[index]);}
}
}
Then, with a simple helper method like this:
ArrayWrapper<T, TField> Wrap<T, TField>(T[] array, Func<T, TField> getField)
{
return new ArrayWrapper<T, TField>(array, getField);
}
You could create an object like this:
var data = new
{
time = Wrap(array_of_packet, p => p.time),
field1 = Wrap(array_of_packet, p => p.field1),
field2 = Wrap(array_of_packet, p => p.field2)
};
... which could be used the way you want:
Plot(data.time, data.field1);
Depending on your specific needs, you could elaborate on this in a number of ways:
IList<TField>
so that Plot()
can be written in a way that's agnostic of the underlying type. (Arrays already implement IList<TField>
.) Func<,>
), you could add where T is struct
to the ArrayWrapper
definition, and have the ArrayWrapper
take a byte offset as its constructor parameter, and do some unsafe
magic to access the field's data more quickly.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.