Reputation: 161
I have a Row object which contains a list of values (columns) stored in a RowValue object. I would like to sort this list based on the value for the column marked as the first.
The RowValue object has a property named 'key' which is a Column object that contains the validation rules. It has another property named 'value' which is the string or numeric value of the column.
The Column validation rules also contain a property named 'display_order' which tells me what order to show the columns in a grid.
I want to sort my List based on the value of the first column in ascending order. Basically, I want to sort on value for the column with the minimum 'display_order' value.
Row object:
public class Row
{
public List<RowValue> Values { get; set; } = new List<RowValue>();
}
RowValue:
public class RowValue
{
public Column key { get; set; }
public string value { get; set; }
}
Column:
public class Column
{
public string name;
public ColumnValidation ColumnValidation;
}
And finally, ColumnValidation:
public class ColumnValidation
{
public string column_label;
public DataTypeEnum data_type;
public int width;
public int decimal_places;
public int display_order;
public string calculation_formula;
public string edit_style;
public string default_value;
public decimal? minimum_value;
public decimal? maximum_value;
public bool is_column_nullable = false;
public bool inherit_values = false;
public bool display_column = false;
public bool is_editable = false;
public int column_style;
public string code_table_name;
public string code_display_name;
public string code_data_column_name;
}
I'm trying to reorder my rows with something like this but it doesn't seem to be working:
// reorder rows
// get the column definition for the first column
Column firstColumn = rows.Select(x => x.Values).FirstOrDefault().OrderBy(x => x.key.ColumnValidation.display_order).Select(x => x.key).FirstOrDefault();
rows = rows.OrderBy(x => x.Values.OrderBy(y => y.key.ColumnValidation.display_order).FirstOrDefault().value).ToList();
Upvotes: 0
Views: 116
Reputation: 30512
So every Row
has zero or more RowValues
. Every RowValue
has a Column
and a Value
. And every Column
has a DisplayOrder
You want for every Row, the Value of the Column with the lowest DisplayOrder. Then OrderBy these Values.
IEnumerable<Row> rows = ...
var result = rows.Select(row => new
{
OriginalRow = row,
// every row has zero or more Values
// every RowValue has a Key.ColumnValidation.DisplayOrder
// Order the RowValues by Key.ColumnValidation.DisplayOrder
SortValue = row.Values
.Orderby(rowValue => rowValue.Key.ColumnValidation.DisplayOrder)
// from this sorted sequence of RowValues, select the Value
.Select(rowValue => rowValue.Value)
// and keep only the first one, which is the one of the first displayed column
.FirstOrDefault(),
})
So now you have a sequence of items where every item contains an OriginalRow
and aSortValue
. The SortValue is the Value of the RowValue that had the lowest Column DisplayOrder.
Continuing the LINQ:
.OrderBy(selectResult => selectResult.SortedValue)
And if you want only your Original Row:
.Select(orderedSelectResult => orderedSelectResult.OriginalValue);
Upvotes: 1
Reputation: 26936
Assuming you meant to order a List<Row>
by the lowest display_order
of the Row.Values
list, and that you don't need to sort in place, and that every Row.Values
will have the same lowest display_order
value or it is okay to sort against the lowest available for each Row
, you can use LINQ:
var ans = rs.OrderBy(r => r.Values.OrderBy(rv => rv.key.ColumnValidation.display_order)
.First()
.value)
.ToList();
Upvotes: 1
Reputation: 96
As I understand it, you have a list of rows, each of which contains a list of columns with values. These columns have an inherent sort key based on their display orders.
Then, for a given result set, you want to find the column present with the lowest sort order, then using that, sort all the row objects by that column.
I put together some code. I put it in a .NET Fiddle so you can experiment with it. Try changing the sort order keys and see if it matches your request.
Here is the key part of the code:
// find column with lowest sort value that is actually present
// get flat list of all values across rows
var firstColumnLabel = rows.SelectMany(l => l.Values)
// get validation column
.Select(v => v.key.ColumnValidation)
// get label of first column
.OrderBy(v => v.display_order)
.Select(v => v.column_label)
.FirstOrDefault();
// sort rows by this column
// if a row lacks the column, then it gets bumped to the end
var sortedRows = rows
.Select(r => new { r, key = GetSortKey(r, firstColumnLabel) })
// push rows with missing columns to end
.OrderBy(rr => rr.key == null ? 1 : 0)
// now do a secondary sort by the actual key
.ThenBy(rr => rr.key)
// recover original row object without sort key
.Select(rr => rr.r);
// ...
static string GetSortKey(Row r, string column_label) {
var columns = r.Values;
var colForLabel = columns.FirstOrDefault(c => c.key.ColumnValidation.column_label == column_label);
if(colForLabel != null) {
return colForLabel.value;
}
return null;
}
Here is the full code:
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
// some sample data with row values and column validation orders
var sampleRow1 = new (string value, int column_order, string column_label)[] {
("Val 1", 2, "Column B"),
("Val 2", 1, "Column A"),
("Val 30", 5, "Column E")
};
var sampleRow2 = new (string value, int column_order, string column_label)[] {
("Val 1", 2, "Column B"),
("Val 2", 5, "Column E")
};
var sampleRows = new[] { sampleRow1, sampleRow2 };
// build up the row data
var rows = new List<Row>();
foreach(var sampleRow in sampleRows) {
var row = new Row();
rows.Add(row);
row.Values = new List<RowValue>();
foreach(var sampleColumn in sampleRow) {
row.Values.Add(new RowValue {
value = sampleColumn.value,
key = new Column {
ColumnValidation = new ColumnValidation
{
display_order = sampleColumn.column_order,
column_label = sampleColumn.column_label
}
}
});
} // END: build columns in Row
} // END: build list of Row objects
// find column with lowest sort value that is actually present
// get flat list of all values across rows
var firstColumnLabel = rows.SelectMany(l => l.Values)
// get validation column
.Select(v => v.key.ColumnValidation)
// get label of first column
.OrderBy(v => v.display_order)
.Select(v => v.column_label)
.FirstOrDefault();
// sort rows by this column
// if a row lacks the column, then it gets bumped to the end
var sortedRows = rows
.Select(r => new { r, key = GetSortKey(r, firstColumnLabel) })
// push rows with missing columns to end
.OrderBy(rr => rr.key == null ? 1 : 0)
// now do a secondary sort by the actual key
.ThenBy(rr => rr.key)
// recover original row object without sort key
.Select(rr => rr.r);
Console.WriteLine($"We sorted by {firstColumnLabel}");
foreach(var srow in sortedRows) {
Console.WriteLine("Row");
foreach(var col in srow.Values) {
Console.WriteLine($"{col.key.ColumnValidation.column_label} = {col.value}");
}
}
}
static string GetSortKey(Row r, string column_label) {
var columns = r.Values;
var colForLabel = columns.FirstOrDefault(c => c.key.ColumnValidation.column_label == column_label);
if(colForLabel != null) {
return colForLabel.value;
}
return null;
}
}
public class Row
{
public List<RowValue> Values { get; set; }
}
public class RowValue
{
public Column key { get; set; }
public string value { get; set; }
}
public class Column
{
public ColumnValidation ColumnValidation;
}
public class ColumnValidation
{
public string column_label;
public int display_order;
// ...
}
Upvotes: 0