Sorting in Dynamo normally requires extracting values into a separate list, sorting that list, and then reordering the original list to match. Insertion Sort of Property collapses this into a single node: pass a list of objects and the name of any numeric property or field as a string, and get back both the sorted property values and the correspondingly reordered elements.
For example, to sort a list of Dynamo Point objects by their X coordinate, pass the list and the string "X". The node returns the sorted X values and the points reordered accordingly.
Solution
Reflection locates the property or field by name at runtime. An insertion sort then keeps both the value list and the element list in sync — every swap in one list mirrors a swap in the other:
// Sorts a flat list of objects by the value of a named property or field.
// Returns [sortedValues, reorderedElements] — both lists are rearranged together
// so elements stay paired with their property values.
public static object InsertionSortOfItemProperty(object data, string propertyName)
{
if (!(data is IList))
return new object[2] { 0, data };
IList listEntry = (IList)data;
// Reject jagged / nested lists — must be single-dimension
foreach (var item in listEntry)
if (item is IList)
throw new Exception("Provide a single-dimension list of elements");
IList<double> propValues = new List<double>();
foreach (var item in listEntry)
{
Type itemType = item.GetType();
// Use reflection to find property or field by name
PropertyInfo pInfo = itemType.GetProperty(
propertyName,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
FieldInfo fInfo = itemType.GetField(
propertyName,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (pInfo == null && fInfo == null)
throw new Exception("No property or field with that name");
object propValue = pInfo != null ? pInfo.GetValue(item) : fInfo.GetValue(item);
if (!IsNumber(propValue))
throw new Exception(quot;Property is not a number: {propValue}");
propValues.Add(double.Parse(propValue.ToString()));
}
// Insertion sort — moves both propValues and listEntry in tandem
for (int idx = 0; idx < propValues.Count; idx++)
{
double newValue = propValues[idx];
object newValueEntry = listEntry[idx];
int idy = idx;
while (idy > 0 && propValues[idy - 1] > newValue)
{
propValues[idy] = propValues[idy - 1];
listEntry[idy] = listEntry[idy - 1];
idy--;
}
propValues[idy] = newValue;
listEntry[idy] = newValueEntry;
}
return new object[2] { propValues, listEntry };
}