Peter
Haven't got time for a full example, but this will get you thinking.
Consider two lines with 4 points each consisting of an ID, X, Y, and Z field as a structured array (numpy )
The final result shown (dz) is the individual lines.
Note... this is the long way, but the logic is less clear in the short way.
a
array([(1, 0.0, 0.0, 0.0), (1, 1.0, 1.0, 1.0), (1, 2.0, 2.0, 2.0),
(1, 3.0, 3.0, 3.0), (2, 3.0, 3.0, 4.0), (2, 2.0, 2.0, 5.0),
(2, 1.0, 1.0, 6.0), (2, 0.0, 0.0, 7.0)],
dtype=[('ID', '<i8'), ('X', '<f8'), ('Y', '<f8'), ('Z', '<f8')])
ids = np.unique(a['ID'])
ids
array([1, 2], dtype=int64)
lines = [a[a['ID'] == i] for i in ids]
dz = [ln[-1]['Z'] - ln[0]['Z'] for ln in lines]
dz
[3.0, 3.0]