Forum Discussion
Greg_Taylor
Dec 08, 2023Copper Contributor
Searching a complex set of data
I have an Excel File generated from a debase report. Each "Record" in the database fills 6 rows by 15 columns. I want to sort the "records" by cell Row3 Column N. Any idea how to do that?
- LorenzoSilver Contributor
Hi Greg_Taylor
Attached is a Get & Transform aka Power Query option:
// Table let Source = Excel.CurrentWorkbook(){[Name="Table"]}[Content], TableSplit = Table.Split(Source, 6), ToTable = Table.FromList(TableSplit, Splitter.SplitByNothing(), {"RECORD"}, null, ExtraValues.Error ), SortBy = Table.AddColumn(ToTable, "SortBy", each Table.First( Table.Skip([RECORD], 2) )[N] ), SortedRows = Table.Sort(SortBy, {{"SortBy", Order.Ascending}}), RemovedSortBy = Table.RemoveColumns(SortedRows, {"SortBy"}), CombinedRecords = Table.Combine(RemovedSortBy[RECORD]) in CombinedRecords
- Put your data in Table sheet 'Input'
- Switch to sheet 'Output'
- Right-click in a cell below A-O > Refresh
- PeterBartholomew1Silver Contributor
Interesting formula! I don't think I could have created that. Are steps such as
Table.Split(Source, 6)
available from the UI or do you have to know the commands to enter them? At least reading your query caused me to dip into the joys of 'selection' and 'projection' once more with a little more sense of purpose.
One thing that occurs to me is that, if Excel 365 is now Turing complete, I should be able to replicate the action of any PQ step using a suitable defined Lambda function. In this case, a list of tables could be replicated as an array of thunks. Unfortunately replicating the functionality of Table.Combine, though possible, is something of a nightmare. The sooner Excel allows lists of arrays the better!
Talking of nightmares, we should persuade Greg_Taylor to post a sample of his workbook here. The data blocks appear to serve the role of a sequence of forms, separated by blank rows and any field can display across several blank columns before the next set of values are encountered. The set task was to sort the 'forms' but I was sorely tempted to normalise the data format instead.
- LorenzoSilver Contributor
- PeterBartholomew1Silver Contributor
The key feature of the formulas is that they are written for Excel 365. Array formulas are used so that the entire table of data is returned in the required sort order from a single cell and spills out down and to the right.
This is very different from traditional spreadsheet methods in which a single cell is calculated using scalar arithmetic and the formula is copied down and to the right using relative referencing.
This final version uses a Lambda function which collects the references together as a parameter string and means you do not have to look at the formulas, just the results.
= BlockSortλ(data, 6, 3, 14) = LAMBDA(data, blockHeight, keyRow, keyColumn, LET( blockCount, QUOTIENT(ROWS(data), blockHeight), keyRows, SEQUENCE(blockCount, 1, keyRow, blockHeight), keyValue, INDEX(data, keyRows, keyColumn), blockedKey, TOCOL(keyValue + SEQUENCE(1, blockHeight, 0, 0)), SORTBY(data, blockedKey) ) )
You may observe that the whole formula looks more like a code module than a traditional spreadsheet formula and this version is a function stored by name in Name Manager.
If you cannot access 365, similar results may be available to you using PowerQuery.
- PeterBartholomew1Silver Contributor
... or a more 'nuts and bolts' approach:
= LET( blockHeight, 6, blockWidth, 15, blockCount, 4, keyRow, 3, keyColumn, 14, keyRows, SEQUENCE(blockCount, 1, keyRow, blockHeight), keyValue, INDEX(data, keyRows, keyColumn), order, SORTBY(SEQUENCE(blockCount), keyValue), rowNumber, TOCOL(blockHeight*(order-1) + SEQUENCE(1,blockHeight)), CHOOSEROWS(data, rowNumber) )
- Greg_TaylorCopper ContributorThank you SOOO much Mr. Bartholomew. There are about 6000 records.
This is very encouraging; however, I am really rudimentary with Excel, so I don't know where to put this string 🙃.... Do I just put this in the first cell of the file?
I'll experiment in the meantime. Is it possible to give me more "Idiot's Guide" directions? Thank you again
- PeterBartholomew1Silver Contributor
= LET( blockHeight, 6, blockWidth, 15, keyRow, 3, keyColumn, 14, singleRows, WRAPROWS(TOCOL(data), blockHeight*blockWidth), sortedRecords, SORT(singleRows, (keyRow-1)*blockWidth+keyColumn), displayed, WRAPROWS(TOCOL(sortedRecords), blockWidth), displayed )
Another strategy might be required if you have more than 10,000 records